Roving TabIndex
Manages tabindex for keyboard navigation within a group of items. Only the focused item is tabbable; arrow keys move focus between items.
import { createRovingTabIndex } from 'phoundry-ui'; Horizontal Toolbar
Tab into the toolbar, then use ← → to navigate. Focused: Bold
Show code
<script lang="ts">
import { createRovingTabIndex } from 'phoundry-ui';
let focused = $state(0);
const roving = createRovingTabIndex({
orientation: 'horizontal',
loop: true,
onFocus: (_el, idx) => (focused = idx),
});
const items = ['Bold', 'Italic', 'Underline', 'Strikethrough', 'Code'];
</script>
<div use:roving.action class="flex gap-1" role="toolbar">
{#each items as item, i}
<button
data-roving-item
class="px-3 py-1.5 rounded text-xs"
class:bg-accent-primary={focused === i}
>
{item}
</button>
{/each}
</div>Both axes (grid)
orientation="both" wires ↑↓←→; loop=false stops wrapping at edges — good for spatial palettes.
Focused: A1
Show code
const roving = createRovingTabIndex({
orientation: 'both',
loop: false,
itemSelector: '[data-roving-item]',
});
<div use:roving.action class="grid grid-cols-2 gap-1" role="group">
{#each cells as cell}
<button type="button" data-roving-item class="rounded px-2 py-1 text-xs">{cell}</button>
{/each}
</div>Vertical Menu
Use ↑ ↓ to navigate. Home / End jump to first/last.
Show code
<div use:roving.action class="flex flex-col" role="menu">
{#each items as item}
<button role="menuitem" class="px-3 py-2 text-left text-xs rounded hover:bg-surface-raised">
{item}
</button>
{/each}
</div>RovingTabIndexOptions
| Prop | Type | Default | Description |
|---|---|---|---|
| orientation | 'horizontal' | 'vertical' | 'both' | 'vertical' | Arrow key direction for navigation. |
| itemSelector | string | [role] / [data-roving-item] | CSS selector for focusable items within the container. |
| loop | boolean | true | Wrap around when reaching the start or end. |
| onFocus | (element, index) => void | — | Called when an item receives focus. |
Return Value
| Prop | Type | Default | Description |
|---|---|---|---|
| action | Action | — | Svelte action to apply to the container element via use:roving.action. |
| focusItem(index) | (number) => void | — | Programmatically focus a specific item by index. |
| focusedIndex | number (readonly) | — | The currently focused item index. |
Usage tips
- Items are matched by
[role="tab"],[role="menuitem"],[role="option"],[role="treeitem"], or[data-roving-item]by default. - Disabled items (
disabledoraria-disabled="true") are skipped. - Use for toolbars, radio groups, tab lists, and menu navigation patterns.
HomeandEndkeys are supported for jumping to first/last items.- Call
focusItem(index)to programmatically move focus (e.g., after adding/removing items).