Skip to main content
0.23.0
View Zag.js on Github
Join the Discord server

Accordion

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

Sample accordion content
Properties

Features

  • Full keyboard navigation.
  • Can expand one or multiple items.
  • Collapse each accordion item.

Installation

To use the accordion machine in your project, run the following command in your command line:

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

This command will install the framework agnostic accordion logic and the reactive utilities for your framework of choice.

Anatomy

To set up the accordion correctly, you'll need to understand its anatomy and how we name its parts.

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

On a high level, the accordion consists of:

  • Root: The root container for the accordion
  • Item: The container for each accordion item

For each accordion item, it consists of:

  • Trigger: The trigger for the accordion item
  • Content: The content area that is revealed when the trigger is clicked

Usage

First, import the accordion package into your project

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

The accordion package exports two key functions:

  • machine — The state machine logic for the accordion widget.
  • connect — The function that translates the machine's state to JSX attributes and event handlers.

You'll also need to provide a unique id to the useMachine hook. This is used to ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the accordion machine in your project 🔥

import * as accordion from "@zag-js/accordion" import { useMachine, normalizeProps } from "@zag-js/react" const data = [ { title: "Watercraft", content: "Sample accordion content" }, { title: "Automobiles", content: "Sample accordion content" }, { title: "Aircrafts", content: "Sample accordion content" }, ] function Accordion() { const [state, send] = useMachine(accordion.machine({ id: "1" })) const api = accordion.connect(state, send, normalizeProps) return ( <div {...api.rootProps}> {data.map((item) => ( <div {...api.getItemProps({ value: item.title })}> <h3> <button {...api.getItemTriggerProps({ value: item.title })}> {item.title} </button> </h3> <div {...api.getItemContentProps({ value: item.title })}> {item.content} </div> </div> ))} </div> ) }

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 accordions at once

To allow multiple items to be expanded at once, set multiple to true. This mode implicitly sets collapsible to true and ensures that each accordion can be expanded.

const [state, send] = useMachine( accordion.machine({ multiple: true, }), )

Opening specific accordions

To set the value of the accordion(s) that should be opened initially, pass the value property to the machine function.

// for multiple accordions const [state, send] = useMachine( accordion.machine({ multiple: true, value: ["home"], }), ) // for single accordions const [state, send] = useMachine( accordion.machine({ value: "home", }), )

Toggle each accordion item

To collapse an already expanded accordion item by clicking on it, set the context's collapsible property to true.

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

const [state, send] = useMachine( accordion.machine({ collapsible: true, }), )

Listening for changes

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

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

Disabling specific accordion items

To disable a specific accordion, 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 items by passing disabled to the machine's context.

const [state, send] = useMachine( accordion.machine({ disabled: true, }), )

Styling guide

Earlier, we mentioned that each accordion part has a data-part attribute added to them to select and style them in the DOM.

Open and closed state

When an accordion item is expanded or collapsed, a data-state attribute is set on the item, trigger and content elements. This attribute is removed when it is closed.

[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-focused 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 */ }

Methods and Properties

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

  • 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) => ItemStateGets the state of an accordion item.

Edit this page on GitHub

On this page