Skip to content

fix(a11y): clear the known contrast entries in the stories sweep - #143

Merged
TheGreatAxios merged 1 commit into
corbitsdev:mainfrom
pratikbuilds:fix/clear-known-contrast-entries
Oct 31, 2026
Merged

TheGreatAxios merged 1 commit into
corbitsdev:mainfrom
pratikbuilds:fix/clear-known-contrast-entries

Conversation

@pratikbuilds

Copy link
Copy Markdown
Collaborator

Summary

Clears the 18 contrast baselines that #120's measured check added to e2e/stories-a11y.known.json. They came from 9 stories in light and dark, and had three causes.

  • Sidebar badge (a real failure). The orange badge tones (accent, warning, access) laid bg-primary/10 over whatever was below. On a selected row, whose ground is already a 10% primary wash, the label fell to 4.38:1. The tones now use a new static pair, --primary-tint / --primary-tint-foreground, defined as hex in :root, .dark and the dark media block. The pair is mapped in @theme inline and listed in REQUIRED, so the contrast gate checks it like every other X / X-foreground fill. It measures 4.78:1 in light and 4.92:1 in dark, the same look as before on a card.
  • Prompt input (a checker gap). The fallback counted every textarea as painting, so the prompt input's transparent field hid the mirror that shows its words. A text field (a textarea, or an input of type text, search, email, url or tel) now paints only what its style draws: its box, its value or placeholder, and a selection highlight. Where a field's glyphs paint nothing, the elements drawing its words that axe did not judge are sampled too, and their samples follow the targets'. The mirror text and tokens now measure and pass.
  • Accepted, with a reason. The known file is now a map from each key to why it stands. Six entries remain:
    • chat-prompt-input--disabled, light and dark: the mirror of a disabled field is at half opacity (3.07 / 3.96:1). WCAG 1.4.3 exempts inactive controls.
    • primitives-avatar--orbit and --stack-with-status, light and dark: the orbit ring is positioned over the initials and hollowed by a mask. Hit-testing finds its whole box, and the sampler takes a mask as opaque, so the ground under the initials can't be read.

Notes for review

  • New browser fixtures pin the field rule both ways:
    • a field showing its own value or placeholder over text leaves that text unmeasured;
    • a dark mirror under a transparent field measures and passes;
    • a faint one is never passed;
    • the fallback samples the mirror on its own when axe judged none.
  • The caret is ignored when deciding what a field paints.
  • The orange badges keep border-primary-emphasis/40. That border is decorative, not text.
  • --primary-tint doesn't change in the warm and cool themes, like --primary: those themes shift only surfaces.

Verification

  • bun run check, bun run build, bun run contrast-test and bun run dep-guard pass.
  • bun run test:e2e passes: 168 Playwright tests, including the Storybook axe sweep in light and dark.
  • With the known file emptied, the sweep fails on exactly the 6 noted entries and nothing else.

Closes #138

The orange badge tones laid a translucent primary wash over whatever was
below, so on a selected sidebar row the two washes stacked and the label
fell to 4.38:1. They now sit on --primary-tint with
--primary-tint-foreground, a static hex pair per mode that the contrast
gate checks like every other fill (4.78:1 light, 4.92:1 dark).

The measured fallback treated every textarea as painting, so the
prompt input's transparent field hid the mirror that shows its words. A
text field now paints only what its style draws: its box, its value or
placeholder, and a selection. Where a field's glyphs paint nothing, the
elements drawing its words that axe did not judge are sampled too.

The known file maps each accepted violation to why it stands: the
disabled prompt's half-opacity mirror (inactive controls are exempt from
WCAG 1.4.3) and the avatar orbit, whose masked ring covers the initials
in a way the sampler cannot see through.
@corbits-triage

corbits-triage Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Triage: Pass

No changes needed from you. A maintainer will review this pull request.

@TheGreatAxios TheGreatAxios left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review · Approve

Replaces translucent orange badge washes with static --primary-tint / --primary-tint-foreground tokens, updates the contrast sampler so text fields only paint visible glyphs and queue unjudged underlying mirrors, and reduces e2e/stories-a11y.known.json to six documented entries.

Findings

  • e2e/contrast-dom.ts:127 (informational) — fieldGlyphs checks resolve(getComputedStyle(field, "::placeholder").color)[3] > 0 without checking -webkit-text-fill-color, whereas sample at line 447 checks lettering.getPropertyValue("-webkit-text-fill-color") || lettering.color.
  • e2e/contrast-dom.ts:474 (informational) — mirrored: drawers.size > 0 is set unconditionally even when clip !== undefined prevented queueing drawers at line 463.

@TheGreatAxios
TheGreatAxios merged commit 9abbf85 into corbitsdev:main Oct 31, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clear the 18 known contrast entries added by the measured axe check

2 participants