Accordion
Accessible, unstyled WAI-ARIA Accordion built on the Collapsible contract.
| Package | @vizejs/ui/accordion |
| Maturity | stable |
| Own the source | vize lib pull accordion |
| Requires | collapsible, collection, context, controllable-state, id, primitive |
| Aliases | accordion, expansion panel, disclosure group, faq |
| Covers | WAI-ARIA Accordion, Radix UI Accordion, Reka UI Accordion, HTML hidden=until-found |
Usage
import { Accordion, AccordionRoot, AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger } from "@vizejs/ui/accordion";
Or copy the source into your project with vize lib pull accordion (see Source Distribution).
API
Accordion<Value extends AccordionValue = string, Type extends AccordionType = 'single'>
Source: src/families/disclosure/accordion/accordion-root.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
type (required) |
Type |
required |
Whether one ("single") or many ("multiple") items may be open. Selects the model shape: Value | null or readonly Value[]. |
id |
string | null |
undefined |
Consumer-owned Accordion base id. null and undefined select a deterministic fallback. |
modelValue |
AccordionModelValue<Value, Type> |
undefined |
Controlled open item(s). undefined selects uncontrolled behavior. |
defaultValue |
AccordionModelValue<Value, Type> |
undefined |
Initial open item(s) for uncontrolled use. |
disabled |
boolean |
false |
Disable user activation of every item while preserving open state. |
collapsible |
boolean |
false |
Let users collapse the open item of a single accordion. multiple accordions are always collapsible. |
orientation |
AccordionOrientation |
"vertical" |
Axis used by arrow-key focus navigation between triggers. |
dir |
AccordionDirection |
undefined |
Reading direction used for horizontal arrow-key navigation. undefined inherits DirectionProvider/LocaleProvider, then "ltr". |
loop |
boolean |
true |
Whether arrow-key navigation wraps at the first and last enabled trigger. |
hiddenUntilFound |
boolean |
false |
Keep closed panels searchable with hidden="until-found"; a find-in-page or fragment match expands the item through beforematch. |
headingLevel |
AccordionHeadingLevel |
3 |
Default native heading level rendered by AccordionHeader. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue |
[value: AccordionModelValue<Value, Type>] |
Fired when the open item(s) request a new controlled value. |
value-change |
[ value: AccordionModelValue<Value, Type>, previous: AccordionModelValue<Value, Type>, nativeEvent: Event | null, ] |
Fired after any distinct open-item request. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
AccordionSlotState<Value, Type> |
Compound AccordionItem children. Receives the current model and configuration. |
Exposed
| Member | Type | Description |
|---|---|---|
collapse |
— | |
collapseAll |
— | |
expand |
— | |
expandAll |
— | |
focus |
— | |
id |
— | |
isOpen |
— | |
openValues |
— | |
setValue |
— | |
toggle |
— | |
type |
— | |
value |
— |
AccordionRoot<Value extends AccordionValue = string, Type extends AccordionType = 'single'>
Source: src/families/disclosure/accordion/accordion-root.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
type (required) |
Type |
required |
Whether one ("single") or many ("multiple") items may be open. Selects the model shape: Value | null or readonly Value[]. |
id |
string | null |
undefined |
Consumer-owned Accordion base id. null and undefined select a deterministic fallback. |
modelValue |
AccordionModelValue<Value, Type> |
undefined |
Controlled open item(s). undefined selects uncontrolled behavior. |
defaultValue |
AccordionModelValue<Value, Type> |
undefined |
Initial open item(s) for uncontrolled use. |
disabled |
boolean |
false |
Disable user activation of every item while preserving open state. |
collapsible |
boolean |
false |
Let users collapse the open item of a single accordion. multiple accordions are always collapsible. |
orientation |
AccordionOrientation |
"vertical" |
Axis used by arrow-key focus navigation between triggers. |
dir |
AccordionDirection |
undefined |
Reading direction used for horizontal arrow-key navigation. undefined inherits DirectionProvider/LocaleProvider, then "ltr". |
loop |
boolean |
true |
Whether arrow-key navigation wraps at the first and last enabled trigger. |
hiddenUntilFound |
boolean |
false |
Keep closed panels searchable with hidden="until-found"; a find-in-page or fragment match expands the item through beforematch. |
headingLevel |
AccordionHeadingLevel |
3 |
Default native heading level rendered by AccordionHeader. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue |
[value: AccordionModelValue<Value, Type>] |
Fired when the open item(s) request a new controlled value. |
value-change |
[ value: AccordionModelValue<Value, Type>, previous: AccordionModelValue<Value, Type>, nativeEvent: Event | null, ] |
Fired after any distinct open-item request. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
AccordionSlotState<Value, Type> |
Compound AccordionItem children. Receives the current model and configuration. |
Exposed
| Member | Type | Description |
|---|---|---|
id |
string |
Root-owned base id for the Accordion family. |
type |
Type |
Selection mode. |
value |
AccordionModelValue<Value, Type> |
Current model value in the shape selected by type. |
openValues |
readonly Value[] |
Every open item value, regardless of type. |
isOpen |
(value: Value) => boolean |
Whether the item with value is expanded. |
setValue |
(value: AccordionModelValue<Value, Type>, event?: Event | null) => boolean |
Replace the model value, bypassing the collapsible guard. Returns whether it changed. |
expand |
(value: Value, event?: Event | null) => boolean |
Expand one item. In single mode this collapses the previously open item. |
collapse |
(value: Value, event?: Event | null) => boolean |
Collapse one item, respecting collapsible in single mode. |
toggle |
(value: Value, event?: Event | null) => boolean |
Toggle one item, respecting collapsible in single mode. |
expandAll |
(event?: Event | null) => boolean |
Expand every registered enabled item. single accordions return false. |
collapseAll |
(event?: Event | null) => boolean |
Collapse every item, respecting collapsible in single mode. |
focus |
(value?: Value, options?: FocusOptions) => boolean |
Focus the trigger for value, or the first enabled trigger. |
AccordionContent
Source: src/families/disclosure/accordion/accordion-content.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
role |
AccordionContentRole | null |
"region" |
Landmark role for the panel. null renders a plain div; prefer null when an accordion has many panels to avoid landmark proliferation. |
hiddenUntilFound |
boolean |
undefined |
Keep this closed panel searchable with hidden="until-found". undefined uses the root hiddenUntilFound. |
ariaLabel |
string |
undefined |
Accessible name when no visible label or aria-labelledby supplies one. |
ariaLabelledby |
string | null |
undefined |
Space-separated ids that label the panel. null omits the default trigger id. |
ariaDescribedby |
string |
undefined |
Space-separated ids that describe the panel. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
AccordionItemSlotState |
Panel contents. Receives the item state. |
Exposed
| Member | Type | Description |
|---|---|---|
value |
AccordionValue |
Item identity. |
open |
boolean |
Whether the item panel is expanded. |
disabled |
boolean |
Whether user activation is disabled for this item. |
locked |
boolean |
Whether the trigger is the open item of a non-collapsible single accordion and therefore reports aria-disabled="true". |
state |
AccordionItemState |
Stable state token for styling and tests. |
element |
HTMLDivElement | null |
Rendered content element. |
hiddenUntilFound |
boolean |
Whether closed content stays searchable through hidden="until-found". |
AccordionHeader
Source: src/families/disclosure/accordion/accordion-header.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
level |
AccordionHeadingLevel |
undefined |
Native heading level. undefined uses the root headingLevel. |
as |
PrimitiveAs |
undefined |
Element or component to render instead of the native h${level}. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
AccordionItemSlotState |
Heading contents, normally one AccordionTrigger. Receives the item state. |
Exposed
| Member | Type | Description |
|---|---|---|
element |
Element | null |
Rendered heading element or component instance. |
AccordionItem
Source: src/families/disclosure/accordion/accordion-item.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value (required) |
AccordionValue |
required |
Item identity used by the Accordion model. |
disabled |
boolean |
false |
Disable user activation of this item while preserving its open state. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
AccordionItemSlotState |
AccordionHeader and AccordionContent children. Receives the item state. |
Exposed
| Member | Type | Description |
|---|---|---|
value |
AccordionValue |
Item identity. |
open |
boolean |
Whether the item panel is expanded. |
disabled |
boolean |
Whether user activation is disabled for this item. |
locked |
boolean |
Whether the trigger is the open item of a non-collapsible single accordion and therefore reports aria-disabled="true". |
state |
AccordionItemState |
Stable state token for styling and tests. |
triggerId |
string |
Id wired to the item trigger. |
contentId |
string |
Id wired to the item content. |
element |
HTMLDivElement | null |
Rendered item element. |
expand |
(event?: Event | null) => boolean |
Request expansion. |
collapse |
(event?: Event | null) => boolean |
Request collapse, respecting collapsible in single mode. |
toggle |
(event?: Event | null) => boolean |
Request the opposite open state. |
AccordionTrigger
Source: src/families/disclosure/accordion/accordion-trigger.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
ariaLabel |
string |
undefined |
Accessible name when no visible label supplies one. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label the trigger. |
Events
| Event | Payload | Description |
|---|---|---|
click |
[nativeEvent: MouseEvent] |
Fired before the trigger requests a toggle. Call preventDefault() to keep state unchanged. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
AccordionItemSlotState |
Trigger contents. Receives the item state. |
Exposed
| Member | Type | Description |
|---|---|---|
element |
HTMLButtonElement | null |
Rendered native button. |
focus |
(options?: FocusOptions) => void |
Move focus to the trigger. |
Behavior
Normative behavior for the @vizejs/ui/accordion compound primitive, following the
WAI-ARIA APG Accordion pattern.
Every row is proven by the named mounted-DOM, SSR, or compile-time test.
Accordion is built on the Collapsible contract: each AccordionItem provides the
Collapsible context, so CollapsibleTrigger and CollapsibleContent also work inside an
item. Native <details name> exclusive groups are intentionally not used: they cannot
express controlled state, the non-collapsible single mode, heading structure around the
trigger, or arrow-key navigation. hidden="until-found" keeps find-in-page support.
| State x input | Observable outcome | Proven by |
|---|---|---|
| any render | Root, item, trigger, and content ids derive from the root id and item value; the trigger is a native button inside a native h3 heading. |
renders APG accordion semantics with deterministic ids and native headings |
| open item | Trigger reports aria-expanded="true" and aria-controls; content is a region labelled by the trigger and has no hidden. |
renders APG accordion semantics with deterministic ids and native headings |
type="single", not collapsible, click on the open trigger |
State is unchanged; the open trigger reports aria-disabled="true" and data-locked. |
single accordion switches items and locks the open item unless collapsible |
type="single", click on a closed trigger |
The clicked item opens, the previous one closes, and update:modelValue plus value-change report the scalar model and native event. |
single accordion switches items and locks the open item unless collapsible |
type="single", collapsible, click on the open trigger |
The item closes and the model becomes null. |
collapsible single accordion collapses the open item to null |
type="multiple", clicks |
Items open and close independently; the model is a readonly list in opening order. | multiple accordion keeps independent items open and emits readonly lists |
controlled modelValue |
Requests emit the next model but rendered state follows the prop until the parent accepts it. | controlled accordion waits for the parent to accept each request |
| Enter or Space on a trigger | Native button activation toggles once per key press. | native Enter and Space activation toggle the focused trigger once |
| ArrowDown / ArrowUp on a vertical trigger | Focus moves to the next or previous enabled trigger, skipping disabled items and wrapping when loop; horizontal arrows are ignored. |
arrow keys, Home, and End move focus between enabled triggers with wrapping |
| Home / End on a trigger | Focus moves to the first or last enabled trigger. | arrow keys, Home, and End move focus between enabled triggers with wrapping |
orientation="horizontal" with dir="rtl"; loop=false at edge |
ArrowLeft moves forward in RTL; at a non-looping edge the key is not consumed and focus stays. | horizontal navigation follows reading direction and loop can stop at the edges |
| disabled root or item | Triggers use native disabled, leave the tab order, and user activation emits nothing. |
disabled roots and items block user activation with native disabled buttons |
trigger click handler calls preventDefault() |
The item does not toggle and no model event is emitted. | trigger click is preventable before the item toggles |
hiddenUntilFound, closed panel after mount |
Panel carries hidden="until-found"; a beforematch event expands the item (even when disabled) and re-closing restores the keyword. |
hidden until-found keeps closed panels searchable and beforematch expands them |
hiddenUntilFound=false |
Closed panels use plain hidden. |
hidden until-found keeps closed panels searchable and beforematch expands them |
| open panel after mount | --vize-accordion-content-height and --vize-accordion-content-width publish the measured panel size for consumer animations. |
content publishes measured size variables and supports role opt-out |
AccordionContent role=null |
Panel renders without a landmark role or default label. | content publishes measured size variables and supports role opt-out |
root headingLevel, header level |
Header renders h{level} with data-level; numeric and non-id-safe values get stable, hashed id segments. |
heading level follows the root default and per-header overrides |
| root expose | expand, collapse, toggle, expandAll, collapseAll, setValue, focus, isOpen, value, and openValues drive and read state. |
root and item expose typed programmatic controls |
type="single" root expose |
expandAll returns false; collapseAll respects collapsible; setValue bypasses the collapsible guard. |
single roots refuse expandAll and keep collapseAll behind collapsible |
| Collapsible parts inside an item | CollapsibleTrigger and CollapsibleContent read the item's ids and state and drive the accordion model. |
items publish the Collapsible contract to Collapsible parts |
| parts outside their provider | Mounting throws VIZE_UI_CONTEXT_MISSING. |
accordion parts require their providers |
| SSR | Isolated requests render byte-identical markup with deterministic ids, native hidden, and no measured style variables. |
renders byte-identical accordion markup across isolated SSR requests |
hydration with hiddenUntilFound |
Hydration reuses server nodes with zero warnings, then upgrades closed panels to hidden="until-found". |
hydrates without mismatches and upgrades closed panels to hidden until-found |
| generic typing | type selects Value | null or readonly Value[]; item values are inferred from modelValue/defaultValue; invalid shapes are rejected. |
src/families/disclosure/accordion/accordion.types.test-d.ts |
| DOM/SSR/Vapor | Every part compiles in each renderer lane without handwritten render functions. | scripts/check-renderers.ts |
Components
| Component | State x input | Outcome |
|---|---|---|
accordion-root.vue |
controlled or uncontrolled model | Owns open items, deterministic ids, keyboard navigation, and emits update:modelValue/value-change. |
accordion-item.vue |
registered value |
Publishes item and Collapsible contexts, data-state, and data-disabled. |
accordion-header.vue |
root headingLevel or level |
Renders the native heading around the trigger. |
accordion-trigger.vue |
click, Enter/Space, arrows, Home/End | Toggles its item through native button activation and moves focus between enabled triggers. |
accordion-content.vue |
open, closed, hiddenUntilFound |
Shows or hides the labelled panel, applies hidden="until-found" after mount, and expands on beforematch. |
Public Root Props
| Prop | Type | Default | Contract |
|---|---|---|---|
type |
"single" | "multiple" |
required | Selection mode and model shape. |
id |
string | null |
undefined |
Consumer-owned base id; null/undefined use the deterministic fallback. |
modelValue |
Value | null or readonly Value[] |
undefined |
Controlled open item(s). |
defaultValue |
Value | null or readonly Value[] |
undefined |
Initial uncontrolled open item(s). |
disabled |
boolean |
false |
Disables user activation of every item. |
collapsible |
boolean |
false |
Lets a single accordion collapse its open item. |
orientation |
"vertical" | "horizontal" |
"vertical" |
Arrow-key axis. |
dir |
"ltr" | "rtl" |
undefined |
Reading direction; inherits DirectionProvider/LocaleProvider, then "ltr". |
loop |
boolean |
true |
Wrap arrow-key navigation. |
hiddenUntilFound |
boolean |
false |
Closed panels use hidden="until-found" after mount. |
headingLevel |
1 | 2 | 3 | 4 | 5 | 6 |
3 |
Default AccordionHeader level. |
Events
| Event | Payload | Contract |
|---|---|---|
update:modelValue |
[value] |
Emitted for every distinct model request. |
value-change |
[value, previous, nativeEvent | null] |
Emitted after every distinct model request. |
click (trigger) |
[nativeEvent: MouseEvent] |
Preventable before the trigger toggles its item. |
Parts And Data
| Target | Public contract |
|---|---|
| Root | part="root", data-vize-ui="accordion-root", data-type, data-orientation, data-disabled, dir |
| Item | part="item", data-vize-ui="accordion-item", data-state, data-orientation, data-disabled |
| Header | part="header", data-vize-ui="accordion-header", data-level, data-state, data-orientation, data-disabled |
| Trigger | part="trigger", data-vize-ui="accordion-trigger", data-state, data-orientation, data-disabled, data-locked |
| Content | part="content", data-vize-ui="accordion-content", data-state, data-hidden-until-found, --vize-accordion-content-height/-width |
Accordion ships no stylesheet. Consumers own all visual styling.