Skip to content

🔲 a11y: Form-Control Outlines Clear 3:1 in Every Palette - #16377

Merged
berry-13 merged 4 commits into
canaryfrom
followup/102-16262-border-medium-outlines-form-controls-below
Sep 25, 2026
Merged

berry-13 merged 4 commits into
canaryfrom
followup/102-16262-border-medium-outlines-form-controls-below

Conversation

@berry-13

Copy link
Copy Markdown
Collaborator

Summary

The shared form controls (Input, Textarea, Select, Dropdown, ControlCombobox, SecretInput, SelectDropDown, InputOTP) drew their only visible edge with border-light or border-medium, and neither clears the WCAG 1.4.11 3:1 non-text floor in any bundled palette: default light border-medium is 1.59:1 on white, and the dark field outline is about 1.2:1 on the dialog. Those roles also paint separators and card edges, which #16244 deliberately keeps one step off the page in dark, so raising them was not the fix.

This adds a border-control theme role that only the control primitives use. Every palette gives it a value that clears 3:1 on every canvas a form can sit on (default 3.12:1, dark 3.25:1, ClickHouse 3.42:1 and 3.73:1 from its own slate and neutral scales, high contrast 21:1). The package ships the stock light and dark defaults, so the outline holds with no theme definition. A custom theme that sets its own border-medium but not the new role keeps the outline it already had. Separator roles are unchanged.

Follow-up to berry-13#102, raised on #16262.

Type of change

  • Bug fix

Testing

Tested environments/configuration:

  • Chromium, lc dev stack on this branch, stock theme in light and dark, Settings > General dropdowns

Automated tests:

  • semanticTokens.spec.ts: new 3:1 floor for border-control on every canvas in default, dark, both high-contrast modes and ClickHouse light and dark (fails on the old border-medium value, passes now), plus a check that the package CSS defaults match the registry
  • registry.spec.ts and applyTheme.spec.ts: fallback to a theme's own border-medium, explicit value preserved, bundled value when a theme sets no border
  • e2e/specs/mock/scenarios/control-border.spec.ts: a real Settings dropdown measured against its painted surface in all six palettes, dark separators unchanged, custom-theme fallback
  • npx jest src/theme src/components in packages/client: 46 suites, 574 tests pass
  • npx tsc --noEmit in packages/client, eslint, prettier and sort-imports on touched files: clean

Screenshots / recordings

Settings > General, stock theme. The dropdown outlines change; the header separator does not.

Before After
Light Light before Light after
Dark Dark before Dark after

Risk / compatibility

Fields and select triggers get a darker outline in light and a lighter one in dark; that is the intended change. The new role's stock defaults live in packages/client/src/theme/controls.css, loaded by ThemeProvider the way highContrast.css is, rather than in client/src/style.css. Stored and environment themes that name border-medium keep their previous control outline until they name border-control.

Not in this change: app call sites that pass their own border-border-light or border-border-medium to a control (preset and memory dialogs, prompt and skill forms, agent list and a few others) still override the role, as do InputNumber and FilterInput. Clearing them lowers eslint-suppressions.json counts, which an open stack owns, so that sweep follows once it lands. Error-state (border-border-destructive) and deliberately borderless inline fields are unaffected.

Checklist

  • I reviewed my own changes
  • Relevant tests have been added or updated
  • Existing relevant tests pass
  • The change does not introduce new warnings or errors

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-25T19:33:11.802106Z 8d98b45 New commits
🔒 Security Review ✅ Completed 2026-09-25T18:56:38.875015Z 9d3afac PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9d3afacfe2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/client/src/theme/registry.ts Outdated
Comment on lines +557 to +559
customColors?.['rgb-border-control'] === undefined &&
customColors?.['rgb-border-medium'] !== undefined
? { 'rgb-border-control': customColors['rgb-border-medium'] }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve legacy light-border themes

When a stored or environment theme predating this token provides rgb-border-light but omits rgb-border-medium, this fallback leaves border-control at the bundled gray; when both differ, it substitutes the medium value. Before this commit, Field (and therefore Input/Textarea), Dropdown, ControlCombobox, SecretInput, and SelectDropDown all used border-light, so restoring such a theme now discards its configured control outline and can make controls indistinguishable on its custom surfaces. The same medium-only condition is duplicated in applyTheme.ts; the compatibility mapping needs to account for the controls that previously consumed border-light.

AGENTS.md reference: AGENTS.md:L31-L34

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 37c3687 (with ed24833): the legacy fallback now weighs the theme's border-light first, then border-medium, the bundled role and its text, keeping the first that clears 3:1 on its own canvases, in both resolveTheme and applyTheme; registry.spec/applyTheme.spec cover light-only, quiet and illegible themes, and all 8 control-border scenarios pass on 37c3687.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e59cb96280

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/client/src/components/Field.ts
border-medium and border-light were the only visible edge on the shared
form controls, and neither clears the WCAG 1.4.11 3:1 non-text floor in
any palette. Raising them would also darken every separator and card edge,
which the quieter dark borders deliberately keep one step off the page.

border-control is a new theme role for the outline of a field, select
trigger, dropdown, combobox trigger and OTP slot. Every bundled palette
gives it a value that clears 3:1 on each canvas a form can sit on, the
package ships the stock light and dark defaults so the outline holds before
and without a theme definition, and a custom theme that paints its own
medium border but not the new role keeps the outline it drew.

semanticTokens.spec.ts holds the 3:1 floor for the role in all six modes.
A theme that paints its own borders but predates border-control took its
medium border as the control outline, and a quiet one left every field
without a visible edge. The fallback now keeps that border only where it
clears 3:1 on the theme's own canvases and otherwise uses the theme's
secondary text, in both resolveTheme and the legacy applyTheme adapter.

The palette scenarios spell out their tags so the runner can find them.
…line

Controls drew border-light (fields, dropdowns, comboboxes) or border-medium
(select, OTP) before border-control existed, so a stored theme that painted
either, or the canvases they sit on, takes the first of its light border,
its medium border, the bundled role or its secondary text that clears 3:1
on its own canvases. A theme that names none of them keeps the bundled role.
…ter one exists

Secondary and primary text join the candidates for a legacy theme's control
outline, and when none clears 3:1 on the theme's canvases the one that
comes closest is used rather than the secondary text by default.
@berry-13
berry-13 force-pushed the followup/102-16262-border-medium-outlines-form-controls-below branch from 37c3687 to 8d98b45 Compare September 25, 2026 19:29
@berry-13
berry-13 merged commit 85910e9 into canary Sep 25, 2026
34 checks passed
@berry-13
berry-13 deleted the followup/102-16262-border-medium-outlines-form-controls-below branch September 25, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant