What is :focus-visible?

:focus-visible: :focus-visible is a CSS pseudo-class that matches a focused element only when the browser decides focus should be shown, typically during keyboard use.

Keyboard users need to see which element has focus; mouse users clicking a button usually do not want a ring flashing around it. :focus cannot tell the two apart, which led many sites to remove outlines entirely and break keyboard navigation. :focus-visible solves this. It matches when an element has focus and the browser's heuristics say an indicator is useful: after keyboard navigation, on text inputs however they were focused, and when script moves focus away from an element that was already showing it. It is supported in all current major browsers.

How it works

css
.button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* hide the ring only for pointer focus */
.button:focus:not(:focus-visible) {
  outline: none;
}

In Tailwind CSS, focus-visible: prefixes any utility: focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2. The related :focus-within matches a parent when any descendant has focus, which is useful for styling a wrapper around an input.

  • Text inputs match :focus-visible on mouse click too, because users need to see where typing will go.
  • Browser default focus styles already use :focus-visible, so do not remove outlines on :focus unless you replace them.
  • Prefer outline for rings where you can. Outlines survive forced colors mode (Windows high contrast); box shadows do not. If your ring is a shadow, add a transparent outline so something still draws.
  • Keep the ring clear of overflow: hidden parents, which clip outlines and offset rings.

Accessibility requirements

WCAG 2.4.7 Focus Visible (level AA) requires a visible indicator for keyboard focus. WCAG 2.2 added 2.4.11 Focus Not Obscured (Minimum, AA), which fails when a sticky header or cookie banner completely hides the focused element, and 2.4.13 Focus Appearance (AAA), which sets size and contrast targets for the indicator. As a working rule, make rings at least 2px thick and at least 3:1 against the colors next to them, in line with non-text contrast.

How MiniDev UI uses it

Focus is a designed state in every component. Buttons get a 2px accent ring with a 2px offset, drawn with focus-visible: utilities; inputs get the accent border plus a 3px accent-soft halo. The global stylesheet sets outline-offset: 2px on :focus-visible so browser defaults stay legible too. Add SkipLink as the first focusable element so keyboard users can jump past navigation, and see ARIA for the semantics that go with visible focus.

ButtonuiShadcn compatible React button on Base UI with eight variants, nine sizes including icon sizes, a pressed state and render prop support for links.npx shadcn@latest add ui.minidev.pro/r/button.json