Skip to content

fix(ui): replace ANSI dim with explicit FG.faint colors; WCAG contrast fixes#2221

Merged
esengine merged 3 commits into
esengine:mainfrom
HUQIANTAO:fix/ansi-dim-contrast
May 29, 2026
Merged

fix(ui): replace ANSI dim with explicit FG.faint colors; WCAG contrast fixes#2221
esengine merged 3 commits into
esengine:mainfrom
HUQIANTAO:fix/ansi-dim-contrast

Conversation

@HUQIANTAO

Copy link
Copy Markdown
Contributor

Summary

Replace the ANSI dim attribute (SGR 2) with explicit FG.faint color references across all UI components. The dim attribute halves foreground brightness, producing near-invisible text on dark terminals where the default foreground is already low-contrast.

Also fixes WCAG AA contrast ratios for fg.faint and fg.meta across all dark themes, and adds OSC 11 terminal background emission so iTerm and similar terminals inherit the theme's surface background.

Extracted from #2171 (closed) — the background fix portion is handled separately by #2182.

Commits

  1. fix(theme): meet WCAG AA contrast for fg.faint and fg.meta across all themes — Adjusts color values in tokens.ts for dark, light, midnight, deep-blue themes to meet 4.5:1 contrast ratio
  2. fix(ui): replace ANSI dim with explicit colors; set terminal background via OSC 11 — ReasoningCard, ToolCard dim→explicit color; chat.tsx emits OSC 11/111 for terminal bg
  3. fix(ui): replace all remaining ANSI dim with explicit FG.faint colors — 22 components: replaces dim prop with color={FG.faint} or conditional color logic

Files changed (26)

tokens.ts (WCAG), chat.tsx (OSC 11), ReasoningCard.tsx, ToolCard.tsx, plus 22 components with dim→FG.faint replacement.

Test plan

  • Dark theme: all "dimmed" text (metadata, timestamps, inactive rows) is readable
  • Light theme: faint text has sufficient contrast
  • iTerm: terminal background matches theme surface (no white gaps)
  • Verify no remaining dim props in UI components

🤖 Generated with Claude Code

@esengine esengine left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The core change is a genuine accessibility win — replacing <Text dim> (SGR 2, which halves brightness and goes near-invisible on dark terminals) with explicit FG.faint across the UI, plus the WCAG-AA contrast bumps to fg.faint/fg.meta. That part I'm happy with (it does change existing themes' faint/meta values, but deliberately and for the better). The dim→FG.faint sweep across the 26 components is consistent and CI's green.

But the PR also bundles a more invasive, separate change with a real failure mode: setting the terminal's background via OSC 11 (\x1b]11;${themeBg}\x07) before render(), restored via OSC 111 only after await waitUntilExit().

  1. Restore isn't crash-safe. The OSC 111 restore only runs on a clean exit. If the process is SIGKILL'd, crashes, or exits on an unhandled signal, the restore never fires and the user's terminal is left repainted with the theme background — a bad state they have to fix manually. Please move the restore to process.on("exit") plus SIGINT/SIGTERM handlers so it fires on every exit path.
  2. Confirm it's intended / consider splitting. Overriding the user's terminal background is more than 'replace ANSI dim' implies — some users deliberately set their terminal bg. Either gate it (opt-in) or at least call it out; ideally it's its own PR separate from the a11y sweep.

The dim→faint + contrast work is ready; it's the OSC 11 terminal-bg override (crash-safety + intent) that I'd want resolved before merge.

HUQIANTAO and others added 3 commits May 29, 2026 12:59
… themes

fg.faint failed WCAG on all 4 dark themes (ratios 1.63-2.56:1, need 4.5:1).
fg.meta failed on midnight (2.35-2.91:1) and was borderline on others.
Dark theme bgElev (#151d2f) was too close to bgInput for surface distinction.

Changes per theme:
- dark: meta #778294→#9aa5b5, faint #4d5666→#8791a3, bgElev #151d2f→#1c2844
- light: meta #6b7280→#5c6371, faint #9ca3af→#666d7b
- midnight: meta #565f89→#9da5bb, faint #414868→#8a92a8
- deep-blue: meta #808080→#909090, faint #606060→#8c8c8c
- high-contrast: already passes, no changes
- ReasoningCard: replace `dim` prop with explicit `FG.sub` color
- ToolCard: replace conditional `dim` with explicit `FG.faint`/`errColor`

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace every remaining `dim` prop across 22 UI components with explicit
`color={FG.faint}` (or conditional color logic where dim was used as a
boolean toggle). The ANSI `dim` attribute (SGR 2) halves brightness of
the foreground color, causing near-invisible text on dark terminals
where the default foreground is already low-contrast.

Components fixed:
- mcp-browse, AtMentionSuggestions, DiffApp, EditConfirm
- McpBrowser, McpHub, McpMarketplace
- PlanReviseConfirm, PlanStepList
- RecordView, ReplayApp, Select, Setup
- SlashArgPicker, SlashSuggestions, SplitDiff
- StatsPanel, Wizard, char-bar, ctx-breakdown
- markdown-view (SpanText ambientDim), primitives (Bar, ContextCell)

For conditional dim (e.g. `dim={isDone}`), replaced with conditional
color logic (`color={isDone ? FG.faint : originalColor}`). The Bar
component's `dim` prop was removed entirely — callers now pass the
appropriate color directly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@HUQIANTAO HUQIANTAO force-pushed the fix/ansi-dim-contrast branch from 5154d2b to 3392895 Compare May 29, 2026 05:02
@HUQIANTAO

Copy link
Copy Markdown
Contributor Author

Updated: the OSC 11 terminal background change has been split out to a separate PR (#2223) with crash-safe restore (process.once("exit") + SIGINT/SIGTERM handlers).

This PR now contains only:

  1. WCAG AA contrast fixes for fg.faint and fg.meta across all themes
  2. dim → explicit FG.faint/FG.sub color replacements in ReasoningCard, ToolCard, and 22 other UI components

@HUQIANTAO HUQIANTAO requested a review from esengine May 29, 2026 05:06

@esengine esengine left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Re-reviewed — you split the OSC 11 terminal-background change out to #2223 (0 OSC refs here now), so this PR is exactly the part I endorsed: the dim→FG.faint sweep across the UI plus the WCAG-AA contrast bumps to fg.faint/fg.meta. That's a clean accessibility win (SGR 2 dim is genuinely near-invisible on dark terminals), CI green. Merging.

@esengine esengine merged commit 9b1e01b into esengine:main May 29, 2026
4 checks passed
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.

2 participants