Skip to main content

An accordion is a vertically stacked set of interactive headings containing a title, content snippet, or thumbnail representing a section of content.

Loading...

Features

  • Full keyboard navigation
  • Supports single and multiple expanded items
  • Supports collapsible items
  • Supports horizontal and vertical orientation

Installation

Install the accordion package:

npm install @zag-js/accordion @zag-js/vue # or yarn add @zag-js/accordion @zag-js/vue

Anatomy

Check the accordion anatomy and part names.

Each part includes a data-part attribute to help identify them in the DOM.

Usage

Import the accordion package:

import * as accordion from "@zag-js/accordion"

The accordion package exports two key functions:

  • machine - State machine logic.
  • connect - Maps machine state to JSX props and event handlers.

Pass a unique id to useMachine so generated element ids stay predictable.

Then use the framework integration helpers:

<script setup> import * as accordion from "@zag-js/accordion" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" const data = [ { title: "Watercraft", content: "Sample accordion content" }, { title: "Automobiles", content: "Sample accordion content" }, { title: "Aircraft", content: "Sample accordion content" }, ] const service = useMachine(accordion.machine, { id: "1" }) const api = computed(() => accordion.connect(service, normalizeProps)) </script> <template> <div ref="ref" v-bind="api.getRootProps()"> <div v-for="item in data" :key="item.id" v-bind="api.getItemProps({ value: item.title })" > <h3> <button v-bind="api.getItemTriggerProps({ value: item.title })"> {{ item.title }} </button> </h3> <div v-bind="api.getItemContentProps({ value: item.title })"> {{ item.content }} </div> </div> </div> </template>

You may have noticed we wrapped each accordion trigger within an h3. This is recommended by the WAI-ARIA design pattern to ensure the accordion has the appropriate hierarchy on the page.

Opening multiple items

Set multiple to true to allow more than one expanded item at a time.

const service = useMachine(accordion.machine, { multiple: true, })

Setting the initial value

Set defaultValue to define expanded items on first render.

// multiple mode const service = useMachine(accordion.machine, { multiple: true, defaultValue: ["home", "about"], }) // single mode const service = useMachine(accordion.machine, { defaultValue: ["home"], })

Controlled accordions

Use value and onValueChange to control expanded items externally.

<script setup> import { ref } from "vue" const valueRef = ref(["home"]) const service = useMachine(accordion.machine, { get value() { return valueRef.value }, onValueChange(details) { valueRef.value = details.value }, }) </script>

Making items collapsible

Set collapsible to true to allow closing an expanded item by clicking it again.

Note: If multiple is true, we internally set collapsible to be true.

const service = useMachine(accordion.machine, { collapsible: true, })

Listening for value changes

When the accordion value changes, the onValueChange callback is invoked.

const service = useMachine(accordion.machine, { onValueChange(details) { // details => { value: string[] } console.log("selected accordion:", details.value) }, })

Listening for focus changes

Use onFocusChange to react when keyboard focus moves between item triggers.

const service = useMachine(accordion.machine, { onFocusChange(details) { // details => { value: string | null } console.log("focused item:", details.value) }, })

Horizontal orientation

Set orientation to horizontal when rendering items side by side.

const service = useMachine(accordion.machine, { orientation: "horizontal", })

Disabling an accordion item

To disable a specific accordion item, pass the disabled: true property to the getItemProps, getItemTriggerProps and getItemContentProps.

When an accordion item is disabled, it is skipped from keyboard navigation and can't be interacted with.

//... <div {...api.getItemProps({ value: "item", disabled: true })}> <h3> <button {...api.getItemTriggerProps({ value: "item", disabled: true })}> Trigger </button> </h3> <div {...api.getItemContentProps({ value: "item", disabled: true })}> Content </div> </div> //...

You can also disable the entire accordion by setting disabled on the machine.

const service = useMachine(accordion.machine, { disabled: true, })

Styling guide

Each part includes a data-part attribute you can target in CSS.

Open and closed state

When an accordion item expands or collapses, data-state is set to open or closed on the item, trigger, and content elements.

[data-part="item"][data-state="open|closed"] { /* styles for the item is open or closed state */ } [data-part="item-trigger"][data-state="open|closed"] { /* styles for the item is open or closed state */ } [data-part="item-content"][data-state="open|closed"] { /* styles for the item is open or closed state */ }

Focused state

When an accordion item's trigger is focused, a data-focus attribute is set on the item and content.

[data-part="item"][data-focus] { /* styles for the item's focus state */ } [data-part="item-trigger"]:focus { /* styles for the trigger's focus state */ } [data-part="item-content"][data-focus] { /* styles for the content's focus state */ }

Creating a component

Create your accordion component by abstracting the machine into your own component.

Usage

Snippet not found :(

Implementation

Use the splitProps utility to separate the machine's props from the component's props.

Snippet not found :(

Methods and Properties

The accordion's api exposes the following methods and properties:

Machine Context

The accordion machine exposes the following context properties:

  • idsPartial<{ root: string; item: (value: string) => string; itemContent: (value: string) => string; itemTrigger: (value: string) => string; }>The ids of the elements in the accordion. Useful for composition.
  • multiplebooleanWhether multiple accordion items can be expanded at the same time.
  • collapsiblebooleanWhether an accordion item can be closed after it has been expanded.
  • valuestring[]The controlled value of the expanded accordion items.
  • defaultValuestring[]The initial value of the expanded accordion items. Use when you don't need to control the value of the accordion.
  • disabledbooleanWhether the accordion items are disabled
  • onValueChange(details: ValueChangeDetails) => voidThe callback fired when the state of expanded/collapsed accordion items changes.
  • onFocusChange(details: FocusChangeDetails) => voidThe callback fired when the focused accordion item changes.
  • orientation"horizontal" | "vertical"The orientation of the accordion items.
  • dir"ltr" | "rtl"The document's text/writing direction.
  • idstringThe unique identifier of the machine.
  • getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

Machine API

The accordion api exposes the following methods:

  • focusedValuestringThe value of the focused accordion item.
  • valuestring[]The value of the accordion
  • setValue(value: string[]) => voidSets the value of the accordion
  • getItemState(props: ItemProps) => ItemStateReturns the state of an accordion item.

Data Attributes

Root
data-scope
accordion
data-part
root
data-orientation
The orientation of the accordion
Item
data-scope
accordion
data-part
item
data-state
"open" | "closed"
data-focus
Present when focused
data-disabled
Present when disabled
data-orientation
The orientation of the item
ItemContent
data-scope
accordion
data-part
item-content
data-state
"open" | "closed"
data-disabled
Present when disabled
data-focus
Present when focused
data-orientation
The orientation of the item
ItemIndicator
data-scope
accordion
data-part
item-indicator
data-state
"open" | "closed"
data-disabled
Present when disabled
data-focus
Present when focused
data-orientation
The orientation of the item
ItemTrigger
data-scope
accordion
data-part
item-trigger
data-orientation
The orientation of the item
data-state
"open" | "closed"

Accessibility

Keyboard Interactions

  • Space
    When focus is on an trigger of a collapsed item, the item is expanded
  • Enter
    When focus is on an trigger of a collapsed section, expands the section.
  • Tab
    Moves focus to the next focusable element
  • Shift + Tab
    Moves focus to the previous focusable element
  • ArrowDown
    Moves focus to the next trigger
  • ArrowUp
    Moves focus to the previous trigger.
  • Home
    When focus is on an trigger, moves focus to the first trigger.
  • End
    When focus is on an trigger, moves focus to the last trigger.
Edit this page on GitHub