Focus Visible
Track keyboard-triggered focus on any element using the native :focus-visible heuristic.
Why use this atom?
- Distinguishes keyboard focus from mouse/touch focus without CDK dependency
- Leverages native browser
:focus-visiblematching — no JavaScript focus origin tracking - Exposes
data-focus-visibleattribute for CSS-only styling - Provides
isFocusVisiblesignal for programmatic access - Can be disabled to suppress tracking
Import
ts
import {AtomFocusVisible} from '@terse-ui/atoms/focus-visible';Usage
html
<button atomFocusVisible>Save</button>When the element receives keyboard focus, data-focus-visible is set. Mouse or touch focus does not trigger it. The attribute is removed on blur.
Template reference
html
<button atomFocusVisible #fv="atomFocusVisible">
{{ fv.isFocusVisible() ? 'Keyboard focused' : 'Click or tab to me' }}
</button>Disabling
html
<button atomFocusVisible [atomFocusVisibleDisabled]="true">No focus tracking</button>As a host directive
ts
@Component({
selector: 'my-button',
hostDirectives: [AtomFocusVisible],
template: `<ng-content />`,
})
export class MyButton {}Styling
css
[atomFocusVisible][data-focus-visible] {
outline: 2px solid var(--ring-color);
outline-offset: 2px;
}The data-focus-visible attribute is only present during keyboard focus. Mouse and touch focus do not trigger it.
How it works
On the (focus) event, the directive checks element.matches(':focus-visible'). This uses the browser's built-in heuristic to determine whether the focus was keyboard-triggered. No CDK FocusMonitor, no global event listeners, no origin tracking — just the platform.
API Reference
WARNING
API reference not found: atoms/focus-visible. Run npx tsx tools/api-extractor/extract.ts --package=atoms to generate it.