UI/UX law
// Interaction & Speed;
Focus Ring
A focus indicator is the keyboard equivalent of a mouse cursor: it only needs to appear for keyboard and other non-pointer input, it has to be genuinely visible against its background, it has to follow the DOM rather than the layout, and a modal has to hold it captive until the modal closes.
Mechanism
Why it happens
A mouse user always knows where they are because the pointer shows it; a keyboard user has no cursor at all, so the focus ring is the only signal of where the next keystroke lands, and hiding it strands them. :focus-visible resolves the usual complaint that a ring "appears on every click": it asks the browser to distinguish how focus arrived and shows the ring for keyboard and programmatic focus while suppressing it for a mouse click, instead of forcing one policy on both populations.
That ring still fails as a signal if it's too thin or too close in colour to read, which is why WCAG 1.4.11 sets a 3:1 non-text contrast floor for it.
It fails again if it never lands where expected: CSS properties like order, flex-direction, or grid placement change what a sighted user sees without touching the DOM, but Tab and Shift+Tab always walk the DOM's source order, so a visually reordered layout sends focus jumping around the screen in a sequence nobody chose.
A modal compounds all of it at once, since the page behind it is still in the DOM and still tabbable once the dialog opens, so without an explicit trap, Tab walks straight through the dialog and out into a page the user can no longer see.
Impact
Why it matters
- A ring that appears on every mouse click reads as broken and gets "fixed" by removing it outright, which strands every keyboard user at once
- A ring under the WCAG 1.4.11 contrast floor, or too thin or too close to the element, is functionally invisible even when it's technically present
- CSS that reorders content visually (order, flex-direction: row-reverse, grid placement) without reordering the DOM sends Tab focus jumping around the screen out of visual sequence
- An open modal with no focus trap lets Tab walk straight through it into the page behind it, which a keyboard user can no longer see
Example
Without vs. with
Delete file?
↳ Tab escapes past Delete, no ring anywhere, into the page behind it
A "Delete file?" dialog opens, but Tab still walks focus out through the page behind it after the last button, and Escape leaves focus lost on <body>, so a keyboard user has to tab back in from the top of the page.
Delete file?
⟲ Tab loops Cancel → Delete → Cancel, Escape returns focus to the trigger
The same dialog moves focus to "Cancel" the instant it opens, Tab and Shift+Tab cycle only between its two buttons while it's open, and Escape (or either button) closes it and returns focus to "Delete file," the control that opened it.
Checklist
How to apply it
Style focus with :focus-visible, not :focus, so a mouse click stays quiet and keyboard or programmatic focus still shows the ring
Give the ring at least 2px of width, at least 2px of offset from the element, and at least 3:1 contrast against its background (WCAG 1.4.11)
Keep visual order and DOM order the same; if a reorder is unavoidable, verify Tab order still matches what's on screen
Trap Tab and Shift+Tab inside an open modal, close it on Escape, and return focus to the element that opened it
Recipe
Code example
Where it shows up