A11y #
Baseline keyboard navigation, single-select, and focus management. Adds ARIA-compliant interaction without the full selection() plugin.
import { createVList, a11y } from "vlist";
const list = createVList({
container: "#app",
item: { height: 48, template: renderItem },
items: data,
}, [a11y()]);
list.on("focus:change", ({ id, index }) => {
console.log("Focused:", id);
});
Config #
No configuration — a11y() takes no arguments.
When to use #
| Scenario | Plugin |
|---|---|
| No keyboard nav needed | Neither — set interactive: false |
| Basic keyboard nav + single-select | a11y() |
| Multi-select, range, Ctrl+A | selection() |
a11y() is a no-op when selection() is active — you don't need both.
Keyboard #
| Key | Action |
|---|---|
| Arrow Up / Down | Move focus by 1 (list), by row (grid), within lane (masonry) |
| Arrow Left / Right | Disabled in list mode. Move by 1 in grid, adjacent lane in masonry |
| Home / End | Jump to first / last item |
| Page Up / Down | Jump by visible page |
| Space / Enter | Toggle selection on focused item |
Navigation adapts automatically when combined with grid() or masonry() — no extra configuration needed.
Events #
| Event | Payload |
|---|---|
focus:change |
{ id: string | number, index: number } |
selection:change |
{ selected: (string | number)[], items: T[] } |
ARIA #
- Sets
aria-activedescendanton the content element to track keyboard focus - Items receive
aria-selectedand CSS classes ({prefix}-item--focused,{prefix}-item--selected) via the item state callback - Requires
interactive: true(the default) forrole="listbox"andtabindex="0"on the content element - Screen reader announcements via a live region ("Item N of M", "Selected", "Deselected")
Notes #
- Group headers are automatically skipped during keyboard navigation
- Click selects the clicked item; focus ring only shown on keyboard navigation
- Focus is restored to the last focused item when the list regains focus
- Priority 55 — runs after
selection()(50) so it can detect and yield to it