Version v2.0.0 Size 1.7 KB gzip Dependencies Zero dependencies
Why Focus?
Composite widgets need consistent keyboard navigation and predictable return focus behavior. Focus centralizes those primitives without coupling to component rendering or framework state.
ts
// Before
list.addEventListener('keydown', (event) => {
// arrow/home/end bookkeeping, disabled filtering, wrapping
});
// After
const nav = createListNavigation({ getItems, onNavigate: ({ item }) => item.focus() });
list.addEventListener('keydown', nav.handleKeydown);| Feature | Per-component navigation | Focus |
|---|---|---|
| Bundle size | n/a | 1.7 KB |
| Zero dependencies | n/a | |
| RTL mirroring | Manual | Built in |
| Typeahead | Manual | Optional via typeahead |
| Focus restoration | Manual capture | captureFocus() / restoreFocus() |
Use Focus when a widget needs arrow-key navigation, Home/End, and controlled focus restoration.
Consider direct focus calls when interaction is a single isolated element with no composite navigation.
Installation
sh
pnpm add @vielzeug/focussh
npm install @vielzeug/focussh
yarn add @vielzeug/focusQuick Start
ts
import { captureFocus, createListNavigation } from '@vielzeug/focus';
const restore = captureFocus();
const nav = createListNavigation({
getItems: () => items,
loop: true,
onNavigate: ({ item }) => item.focus(),
});
container.addEventListener('keydown', nav.handleKeydown);
restore();
nav.dispose();Features
createListNavigation()— reusable composite-widget keyboard navigation- Orientation and direction support — vertical/horizontal/both with LTR/RTL defaults
- Dynamic item queries — disabled filtering and loop control
- Optional typeahead — label-based navigation in key-driven lists
captureFocus()andrestoreFocus()— explicit return-focus helpers