Focus
Track focus state on any element with both general focus and keyboard-only focus detection.
Why use this atom?
- Distinguishes any focus (
data-focus) from keyboard focus (data-focus-visible) - Programmatic focus control via writable
isFocusedsignal —isFocused.set(true)focuses the element - Powered by signality's
elementFocus()with automatic SSR safety and cleanup - Native
:focus-visiblematching for keyboard detection — no CDK dependency
Import
ts
import {AtomFocus} from '@terse-ui/atoms/focus';Usage
html
<button atomFocus>Save</button>When the element receives any focus, data-focus is set. When focus is keyboard-triggered, data-focus-visible is also set. Both are removed on blur.
Template reference
html
<button atomFocus #f="atomFocus">
{{ f.isFocusVisible() ? 'Keyboard focused' : f.isFocused() ? 'Focused' : 'Not focused' }}
</button>Programmatic focus
ts
@Directive({
selector: '[autoFocusOnOpen]',
hostDirectives: [AtomFocus],
})
export class AutoFocusOnOpen {
readonly #focus = inject(AtomFocus);
setFocus() {
this.#focus.isFocused.set(true); // focuses the element
}
removeFocus() {
this.#focus.isFocused.set(false); // blurs the element
}
}Styling
css
[atomFocus][data-focus] {
/* Any focus (mouse, keyboard, programmatic) */
}
[atomFocus][data-focus-visible] {
/* Keyboard focus only — use for focus rings */
outline: 2px solid var(--ring-color);
outline-offset: 2px;
}API Reference
AtomFocus
| Selector | [atomFocus] |
| Exported as | atomFocus |
| Data attributes | data-focus, data-focus-visible |
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
atomFocusDisabled | boolean | Disables focus tracking when true. |
Outputs
| Output | Type | Description |
|---|---|---|
atomFocusDisabledChange | boolean | Disables focus tracking when true. |
Properties
| Property | Type | Description |
|---|---|---|
isFocused | WritableSignal<boolean> (readonly) | Whether the element is currently focused. Writable — set true to focus, false to blur. |
isFocusVisible | Signal<boolean> (readonly) | Whether the element has keyboard-triggered focus. |