v145 · DOM · Focus

Focus's focusVisible option

Chrome 145 adds a focusVisible boolean to the FocusOptions dictionary passed to element.focus(). When true, the browser always paints a focus ring and matches :focus-visible, regardless of input modality. When false, focus is applied silently — no ring shown. This gives JavaScript code explicit control over the focus ring that CSS alone cannot provide.

concepts

  1. Focus Ring Control

    Three buttons that programmatically focus a target element with focusVisible: true, focusVisible: false, and the default (no option). See how the focus ring appears and whether :focus-visible is matched in each case.

  2. Keyboard vs. Mouse Pattern

    A common pattern: show the focus ring when focus was moved via keyboard, hide it when moved by click. Shows how focusVisible lets JavaScript correctly communicate intent to the browser's focus ring system.

  3. Menu Focus Trace

    Custom keyboard menu that calls focus({focusVisible: true}) on arrow-key moves and the silent default on click-driven dismissal. Logs every focus call so you can see the difference.

  4. Accessible Modal

    A modal dialog that opens via mouse click (focusVisible: false) or keyboard shortcut (focusVisible: true). The focus ring appears precisely when expected — check the event log to see which option fired in each case.

why it shipped

The :focus-visible CSS pseudo-class was introduced to let browsers show the focus ring only for keyboard navigation — hiding it after mouse clicks. But JavaScript-triggered focus (element.focus()) has ambiguous intent: was it a keyboard shortcut handler? A screen reader interaction? A mouse click handler? Before Chrome 145, JavaScript had no way to signal which — the browser guessed based on recent input events, often getting it wrong. The focusVisible option in FocusOptions adds explicit intent: pass true to always show the ring (keyboard-intent), false to always suppress it (mouse-intent), or omit to let the browser guess as before.

the API

// Always show focus ring (keyboard intent)
element.focus({ focusVisible: true });

// Always suppress focus ring (mouse intent)
element.focus({ focusVisible: false });

// Default: browser guesses based on recent input modality
element.focus();
element.focus({ preventScroll: true }); // also no focusVisible

// CSS can still customise :focus-visible as normal
button:focus-visible {
  outline: 3px solid cornflowerblue;
  outline-offset: 2px;
}

references