fix(ui-kit): move focus ring to focus-visible on Select/Dialog/Sheet/NavigationMenu - #8335
Conversation
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
…NavigationMenu SelectTrigger, DialogPrimitive.Close, SheetPrimitive.Close, and NavigationMenuTrigger applied their focus ring/highlight on plain focus:, which also fires on mouse-click focus and leaves a lingering ring/highlight after every click — unlike button/input/switch/checkbox/toggle/slider and every other interactive primitive in the kit, which ring on focus-visible:. Moves only the visible ring/highlight classes to focus-visible: (keeping focus:outline-none, which correctly clears the native outline on any focus), with a regression test asserting the corrected class lists. Closes JSONbored#8304
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-24 10:41:25 UTC
Review summary Nits — 4 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. Visual preview
Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy. Scroll preview
A short scroll-through clip (desktop) — click either thumbnail to open the full animation. Evidence for scroll-linked behavior a single screenshot can't show. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|


Summary
SelectTrigger(select.tsx),DialogPrimitive.Close(dialog.tsx),SheetPrimitive.Close(sheet.tsx), andNavigationMenuTrigger(navigation-menu.tsx) applied their focus ring / background highlight on plainfocus:, which fires on mouse-click focus too and leaves a lingering ring/highlight after every click — unlikebutton.tsx,input.tsx,textarea.tsx,switch.tsx,checkbox.tsx,toggle.tsx,slider.tsx, andbadge.tsx, which all ring onfocus-visible:(keyboard/programmatic focus only).focus-visible:at those four sites:focus:ring-* → focus-visible:ring-*(Select/Dialog/Sheet) andfocus:bg-accent focus:text-accent-foreground → focus-visible:*(NavigationMenu).focus:outline-noneis kept as-is (clearing the native outline on any focus is correct and shared by every primitive), and the intentionaldata-[state=open]:focus:bg-accentopen-state compound is untouched. No other className (radius, padding, color tokens) changed.focus-visible-convention.test.tsx: assertsnavigationMenuTriggerStyle()and the renderedSelectTriggernow carryfocus-visible:ring/highlight classes and no barefocus:ring/focus:bg-accent, while keepingfocus:outline-none.Closes #8304
Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Closes #123) — a linked open issue is required for every contributor PR.Validation
git diff --checknpm run actionlintnpm run typechecknpm run test:coveragelocally;codecov/patchrequires ≥99% coverage of the lines AND branches you changed (aim for 100% on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate.npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderateIf any required check was skipped, explain why:
packages/loopover-ui-kit/**(four class renames + one new test).packages/loopover-ui-kitis not in the rootvitest.config.tscoverage.includeand is not Codecov-gated (its ownvitest.config.ts: the acceptance signal is the suite running and passing, not a percentage), sotest:coverage/codecov/patchdo not apply;actionlint,test:workers,build:mcp/test:mcp-pack,ui:openapi:check, andnpm auditare not exercised by a ui-kit-only class change. Locally verified in the package:npm test(4 files / 21 tests, incl. the 2 new),tsc --noEmit, andprettier --checkon the touched files all pass.Safety
UI Evidencesection below with JPG/JPEG or PNG screenshots arranged as organized, captioned, clickable thumbnails. SVG screenshots are not used as review evidence. Review-only screenshots or recordings are not committed to the repository.UI Evidence
This fix has no at-rest visual difference and no difference under mouse interaction at all in the sense a static screenshot captures — the change is purely which focus triggers the ring.
:focus-visibleis a browser-heuristic pseudo-class that, by design, does not match on mouse-click focus, so:SelectTrigger/ theDialogorSheetclose button /NavigationMenuTriggerwith a mouse left a persistent focus ring/highlight after the click (the bug).button/input/switchand every other primitive in the kit.Because the difference is a focus pseudo-class heuristic rather than a rendered-pixel change, the authoritative, machine-checkable evidence is the class-list regression test
focus-visible-convention.test.tsx(part of this PR): it assertsnavigationMenuTriggerStyle()and the renderedSelectTriggernow carry thefocus-visible:ring/highlight classes and no barefocus:ring/focus:bg-accent, while keepingfocus:outline-none. This is the same class-list-assertion evidence conventionstate-views.test.tsx/theme-toggle.test.tsxalready use for ui-kit variant guarantees, and the same shape the sibling accessibility fixes #7015/#7016 were verified with.Notes
.focus-ringutility — mirrors the exactfocus-visible:convention ofbutton.tsx/input.tsx/switch.tsx, matching the "AccordionTrigger has no focus-visible indicator, unlike every other interactive control in ui-kit #7015 AccordionTrigger — unlike every other X in ui-kit" shape.