Skip to content

fix(core): restore visible keyboard focus ring on Collapsible trigger#3722

Merged
cixzhang merged 1 commit into
facebook:mainfrom
bhamodi:a11y/collapsible-focus-ring
Jul 10, 2026
Merged

fix(core): restore visible keyboard focus ring on Collapsible trigger#3722
cixzhang merged 1 commit into
facebook:mainfrom
bhamodi:a11y/collapsible-focus-ring

Conversation

@bhamodi

@bhamodi bhamodi commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Collapsible's trigger is a real <button>, but styles.trigger starts with all: unset (packages/core/src/Collapsible/Collapsible.tsx:54), which wipes the browser's default focus outline. No :focus-visible style was reintroduced anywhere in the file, so keyboard users could Tab to the trigger but saw no focus indicator -- a WCAG 2.4.7 (Focus Visible) failure.

This restores a keyboard-only focus ring on the trigger using the design system's established convention: outline: 2px solid var(--color-accent) with outlineOffset: 2px, both gated on :focus-visible. The treatment mirrors the TabMenu trigger button (packages/core/src/TabList/TabMenu.tsx:93-100), the closest structural analog (another reset trigger button that restores its ring this way), and uses the exact same token, width, style, and offset as Button, Dialog, Pagination, Tab, and Slider. Purely additive; the ring only appears on keyboard focus, so mouse/touch interaction is unchanged.

Changes

  • Collapsible/Collapsible.tsx: add outline / outlineOffset :focus-visible rules to styles.trigger (restores the ring removed by all: unset).

Test plan

StyleX compiles styles to atomic class names, so jsdom cannot assert the computed outline value -- the existing :focus-visible tests in the repo (Slider, Token, FileInput) verify focus behavior by mocking matches(':focus-visible'), not the outline CSS itself. There is no established pattern for asserting a focus-ring style value, so I did not add a brittle class-name-snapshot test.

  • node_modules/.bin/vitest run --root . packages/core/src/Collapsible -- 32 pass (existing suite stays green).
  • node_modules/.bin/tsc --project packages/core/tsconfig.json --noEmit -- clean.
  • node_modules/.bin/eslint packages/core/src/Collapsible/Collapsible.tsx -- clean.
  • Manual verification: Tabbing to the trigger in Storybook should now show the accent focus ring (matching TabMenu). I could not run a browser in this environment, so this step is un-run; the values are copied verbatim from already-shipping components that render the ring correctly.

Notes

Found during a broader a11y audit of core components. Scoped to only the focus-visible style on the Collapsible trigger -- aria-controls wiring is covered separately by #3707, and the chevron/other styling is untouched.

@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

@bhamodi is attempting to deploy a commit to the Meta Open Source Team on Vercel.

A member of the Team first needs to authorize it.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Jul 9, 2026

@cixzhang cixzhang 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.

Thanks @bhamodi — clean :focus-visible ring, verbatim TabMenu match, semantic token, verified against StyleX CAPABILITIES. 🙏

@cixzhang cixzhang merged commit 55fa761 into facebook:main Jul 10, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants