fix(a11y): consistent high-contrast focus rings across all Button variants (WCAG 1.4.11)#3438
Merged
Merged
Conversation
…ns (WCAG 1.4.11) Two same-shape fixes for SC 1.4.11 Non-text Contrast on the Button primitive. Both variants previously composited a ring color over a same-or-similar button background, producing ratios that fail the 3:1 SC threshold: - primary: indigo ring on indigo button (~1:1, effectively invisible) -> white ring with offset against the page surface (~7:1). - destructive: red ring at 70% on red.300 button (~2:1) -> full-opacity red ring with offset against the page (~6:1). The ring-offset-2 + ring-offset-surface-primary pattern puts the ring in a 2px gap between the button and the page so it never blends with either surface. Matches the convention used by Material, Primer, and Atlassian Design System. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
…ants
Follow-up to the primary + destructive focus-ring fix.
- Primary ring switched from ring-white to ring-primary. The white
ring blended with the white page in light mode (button -> white
gap -> white ring -> white page); the new full-opacity indigo
ring is visible against both light and dark page surfaces.
- Secondary, ghost, and table-header variants now also use the
ring-{color} + ring-offset-2 + ring-offset-surface-primary
pattern for visual consistency. The offset puts the ring in a
page-color gap separated from the button.
Pattern is now uniform: button -> page-color gap -> ring (in
button's color family) -> page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Member
Author
|
Ideally, this pattern should extend to all interactive elements. |
Alex-Tideman
approved these changes
May 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Unifies focus-ring styling across all 5 Button variants to fix SC 1.4.11 Non-text Contrast. Previously every variant used a 70% opacity ring with no offset; the primary variant produced an effectively invisible indigo ring (~1:1) on its indigo background, and destructive produced a faint red-on-red ring (~2:1).
Final pattern (applied to all variants)
ring-primaryfor primary/secondary/ghost/table-header,ring-dangerfor destructive). Full opacity instead of/70.surface-primary(white in light mode, black in dark mode) — puts a 2px gap between the button and the ring.Variant changes
ring-primary/70(indigo on indigo, ~1:1)ring-primary+ offset (~7:1 vs page)ring-danger/70(red on red.300, ~2:1)ring-danger+ offset (~6:1 vs page)ring-primary/70, no offsetring-primary+ offset for consistencyring-primary/70, no offsetring-primary+ offset for consistencyring-primary/70, no offsetring-primary+ offset for consistencyNote on the first iteration
Initial commit used
ring-whitefor primary per the audit's recommended Option A. That worked in dark mode but blended with the white page in light mode (button → white gap → white ring → white page). Switched to Option B (ring-primarywith offset) which works in both themes.Audit context
audit-output/issues/1.4.11-button-{primary,destructive}-focus-ring.md. The secondary/ghost/table-header consistency extension is beyond the audit's literal scope but follows directly from the same pattern.Test plan
🤖 Generated with Claude Code