Skip to content

fix(button): use :focus-visible for hover-bg, drop click-focused dark state#7437

Draft
talissoncosta wants to merge 2 commits intomainfrom
fix/button-focus-visible
Draft

fix(button): use :focus-visible for hover-bg, drop click-focused dark state#7437
talissoncosta wants to merge 2 commits intomainfrom
fix/button-focus-visible

Conversation

@talissoncosta
Copy link
Copy Markdown
Contributor

Thanks for submitting a PR! Please check the boxes below:

  • I have read the Contributing Guide.
  • I have added information to `docs/` if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

TL;DR. Primary buttons stay visibly "pressed" after a mouse click until the user clicks elsewhere. Switching the focus-state CSS from `:focus` to `:focus-visible` removes the click-and-stuck appearance while preserving the keyboard-focus indicator.

Cause

_buttons.scss lines 8–11 (pre-fix):

.btn, button.btn {
  &:hover,
  &:focus {
    background-color: \$btn-hover-bg;  // = \$primary600 (darker primary)
  }
}

:focus matches any focus event, including the focus a browser implicitly gives a button after a mouse click. So the flow is:

  1. User clicks a primary button → browser focuses it.
  2. :focus fires → background turns to \$primary600 (darker).
  3. Focus persists until the user clicks elsewhere or tabs away → button stays dark.

Visible on every primary button across the app. Storybook surfaces it most obviously because the button stays in view post-click, but it happens in production too — confirmed by clicking Create Identities on the Identities page and watching the button stay dark.

Fix

Single rule change: :focus:focus-visible.

   &:hover,
-  &:focus {
+  &:focus-visible {
     background-color: \$btn-hover-bg;
   }

:focus-visible is the modern pseudo-class that matches focus only when it arrived via keyboard navigation (Tab) or programmatic focus — not mouse clicks. Browser support is universal across all evergreen browsers.

After the change:

  • Mouse click: button is still focused (browser default) but :focus-visible doesn't match → no darkening → no stuck appearance. ✓
  • Tab key: :focus-visible matches → background darkens → keyboard users see the focus state. ✓ (a11y preserved)
  • :focus-visible { box-shadow: none } rule on the next line stays as-is — same intent (suppress Bootstrap's default focus ring on keyboard focus, since the bg-darkening is the visual indicator).

Out of scope

The :focus references in .btn-project rules (lines 224, 435) are visual focus styles for the project-picker variant. They probably want the same treatment but the .btn-project rendering is more involved than the base button — kept out of this PR to keep the diff focused. Worth a follow-up if Chromatic flags any visual divergence in those stories.

How did you test this code?

  • Reproduced on main by clicking Create Identities on the Identities page and observing the button stay darkened until clicking elsewhere.
  • After the fix: same click no longer leaves the button visibly pressed.
  • Keyboard verification: `Tab` to a button, confirmed the darker background still appears (a11y indicator intact).
  • Chromatic build on this PR will diff every primary/secondary/danger/etc. button snapshot in the design system — worth scrolling through to confirm no surface relies on the old click-focused appearance.

… state

The `.btn:focus` rule was applying the hover-bg colour for any focus
event including mouse clicks. Browsers leave clicked buttons focused
by design, so the button looked permanently pressed until the user
clicked elsewhere — visible on every primary button across the app
(Storybook surfaces it most obviously, but it happens in production
too).

Switching the rule to `:focus-visible` keeps the visual indicator for
keyboard-driven focus (Tab key) while skipping it for mouse clicks.
A11y signal preserved, click-and-stuck appearance gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
flagsmith-frontend-preview Ready Ready Preview, Comment May 6, 2026 0:50am
flagsmith-frontend-staging Ready Ready Preview, Comment May 6, 2026 0:50am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview May 6, 2026 0:50am

Request Review

The previous commit only fixed the base .btn rule. Each theme variant
(secondary, tertiary, danger, success, outline, link, project, icon,
with-icon) defined its own &:hover, &:focus pair, so the click-and-stuck
appearance kept happening on every variant.

Replaces all `:focus` references in _buttons.scss with `:focus-visible`
(except the one inside the explanatory comment). Same fix shape, applied
to the full surface — light and dark themes, every variant, every
custom button class. 19 lines changed in a single SCSS file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix front-end Issue related to the React Front End Dashboard

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant