Skip to content

Headless Core — Accordion

Powers Accordion and and-vanilla-accordion internally.

import { createAccordion } from '@andersseen/headless-components/accordion';
const accordion = createAccordion({
allowMultiple: true,
defaultValue: ['item-1'],
onValueChange: items => console.log('Expanded:', items),
});
accordion.actions.toggle('item-2');
accordion.queries.isExpanded('item-1'); // true
OptionTypeDefaultNotes
allowMultiplebooleanfalse
defaultValuestring[][]Item IDs expanded on creation.
onValueChange(items: string[]) => voidFires after every expand/collapse.
orientation'horizontal' | 'vertical''vertical'
disabledbooleanfalse

expandedItems: Set<string>, orientation, disabled, allowMultiple.

MemberSignatureNotes
actions.toggle(id)(itemId: string) => voidIn single mode, expanding one collapses the rest.
actions.expand(id) / collapse(id)(itemId: string) => void
actions.expandAll()() => voidNo-op today — needs the full item-id list, which the factory doesn’t track (only expanded ones). Use expand(id) per item instead.
actions.collapseAll()() => void
actions.setDisabled(v) / setAllowMultiple(v)(boolean) => void
queries.isExpanded(id)(itemId: string) => boolean
queries.getExpandedItems()() => string[]
GetterReturns
getContainerProps()data-orientation
getTriggerProps(itemId)aria-expanded, aria-controls, aria-disabled, role: 'button', tabindex, data-state, data-disabled
getContentProps(itemId)role: 'region', id, aria-hidden, hidden, data-state

aria-controls/id are paired via createIdGenerator — see Primitives.

handleTriggerKeyDown(event, itemId) toggles on Enter/Space; Home/End call preventDefault() but focus-moving is left to the consuming component (the headless core has no DOM access to focus a sibling trigger).

Toggle "item-1"

Primitives — how the aria-controls/id pair stays in sync.