Skip to content

Headless Core — Tabs

Powers Tabs internally.

import { createTabs } from '@andersseen/headless-components/tabs';
const tabs = createTabs({
defaultValue: 'tab-1',
orientation: 'horizontal',
onValueChange: tabId => console.log('Selected:', tabId),
});
tabs.actions.selectTab('tab-2');
OptionTypeDefaultNotes
defaultValuestringInitially selected tab id.
onValueChange(tabId: string) => void
orientation'horizontal' | 'vertical''horizontal'Swaps which arrow keys move focus.
activationMode'automatic' | 'manual''automatic'Automatic: arrow-focusing a tab selects it immediately.
disabledbooleanfalse

selectedTab: string | null, orientation, activationMode, disabled.

MemberSignature
actions.selectTab(id)(tabId: string) => void
actions.setDisabled(v)(disabled: boolean) => void
actions.setOrientation(v)(orientation: 'horizontal' | 'vertical') => void
actions.setActivationMode(v)(mode: 'automatic' | 'manual') => void
queries.isSelected(id)(tabId: string) => boolean
queries.getSelectedTab()() => string | null
GetterReturns
getContainerProps()data-orientation
getListProps()role: 'tablist', aria-orientation
getTriggerProps(id)role: 'tab', aria-selected, aria-controls, aria-disabled, tabindex (roving — 0 only for the selected tab), id, data-state, data-disabled, data-orientation
getContentProps(id)role: 'tabpanel', aria-labelledby, tabindex: 0, id, hidden, data-state

handleTriggerKeyDown(event, currentTabId, allTabIds) — needs the full id list every call, since the headless core doesn’t track registration order itself. ArrowRight/ArrowLeft (or ArrowDown/ArrowUp when orientation: 'vertical') move focus with wraparound; Home/End jump to the first/last. In automatic mode, moving focus also calls selectTab — actually focusing the resulting element is left to the consuming component (no DOM access here).

Select "tab-1" Select "tab-2"

Sidebar and Navbar implement a similar roving-focus keyboard pattern over a registered item list.