{"slug":"accordion","title":"Accordion","description":"Using the accordion machine in your project.","contentType":"component","framework":"react","content":"An accordion is a vertically stacked set of interactive headings containing a\ntitle, content snippet, or thumbnail representing a section of content.\n\n## Resources\n\n\n[Latest version: v1.31.0](https://www.npmjs.com/package/@zag-js/accordion)\n[Logic Visualizer](https://zag-visualizer.vercel.app/accordion)\n[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/accordion)\n\n\n\n**Features**\n\n- Full keyboard navigation\n- Can expand one or multiple items\n- Collapse each accordion item\n\n## Installation\n\nTo use the accordion machine in your project, run the following command in your\ncommand line:\n\n```bash\nnpm install @zag-js/accordion @zag-js/react\n# or\nyarn add @zag-js/accordion @zag-js/react\n```\n\n## Anatomy\n\nTo set up the accordion correctly, you'll need to understand its anatomy and how\nwe name its parts.\n\n> Each part includes a `data-part` attribute to help identify them in the DOM.\n\n\n\n## Usage\n\nFirst, import the accordion package into your project\n\n```jsx\nimport * as accordion from \"@zag-js/accordion\"\n```\n\nThe accordion package exports two key functions:\n\n- `machine` — The state machine logic for the accordion widget.\n- `connect` — The function that translates the machine's state to JSX attributes\n  and event handlers.\n\n> You'll also need to provide a unique `id` to the `useMachine` hook. This is\n> used to ensure that every part has a unique identifier.\n\nNext, import the required hooks and functions for your framework and use the\naccordion machine in your project 🔥\n\n```jsx\nimport * as accordion from \"@zag-js/accordion\"\nimport { useMachine, normalizeProps } from \"@zag-js/react\"\nimport { useId } from \"react\"\n\nconst data = [\n  { title: \"Watercraft\", content: \"Sample accordion content\" },\n  { title: \"Automobiles\", content: \"Sample accordion content\" },\n  { title: \"Aircraft\", content: \"Sample accordion content\" },\n]\n\nfunction Accordion() {\n  const service = useMachine(accordion.machine, { id: useId() })\n\n  const api = accordion.connect(service, normalizeProps)\n\n  return (\n    <div {...api.getRootProps()}>\n      {data.map((item) => (\n        <div key={item.title} {...api.getItemProps({ value: item.title })}>\n          <h3>\n            <button {...api.getItemTriggerProps({ value: item.title })}>\n              {item.title}\n            </button>\n          </h3>\n          <div {...api.getItemContentProps({ value: item.title })}>\n            {item.content}\n          </div>\n        </div>\n      ))}\n    </div>\n  )\n}\n```\n\nYou may have noticed we wrapped each accordion trigger within an `h3`. This is\nrecommended by the\n[WAI-ARIA](https://www.w3.org/TR/wai-aria-practices-1.1/#wai-aria-roles-states-and-properties)\ndesign pattern to ensure the accordion has the appropriate hierarchy on the\npage.\n\n### Opening multiple accordions at once\n\nTo allow multiple items to be expanded at once, set `multiple` to `true`. This\nmode implicitly sets `collapsible` to `true` and ensures that each accordion can\nbe expanded.\n\n```jsx {2}\nconst service = useMachine(accordion.machine, {\n  multiple: true,\n})\n```\n\n### Opening accordions by default\n\nTo set the value of the accordion(s) that should be opened initially, pass the\n`defaultValue` property to the machine function.\n\n```jsx {3,4,9}\n// for multiple accordions\nconst service = useMachine(accordion.machine, {\n  multiple: true,\n  defaultValue: [\"home\"],\n})\n\n// for single accordions\nconst service = useMachine(accordion.machine, {\n  defaultValue: [\"home\"],\n})\n```\n\n### Controlled accordions\n\nTo control the accordion's value, pass the `value` and `onValueChange`\nproperties to the machine function.\n\n```tsx\nimport { useState } from \"react\"\n\nexport function ControlledAccordion() {\n  const [value, setValue] = useState([\"home\"])\n\n  const service = useMachine(accordion.machine, {\n    value,\n    onValueChange(details) {\n      setValue(details.value)\n    },\n  })\n\n  return (\n    // ...\n  )\n}\n```\n\n### Toggle each accordion item\n\nTo collapse an already expanded accordion item by clicking on it, set the\ncontext's `collapsible` property to `true`.\n\n> Note: If `multiple` is `true`, we internally set `collapsible` to be `true`.\n\n```jsx {2}\nconst service = useMachine(accordion.machine, {\n  collapsible: true,\n})\n```\n\n#### Listening for changes\n\nWhen the accordion value changes, the `onValueChange` callback is invoked.\n\n```jsx {2-5}\nconst service = useMachine(accordion.machine, {\n  onValueChange(details) {\n    // details => { value: string[] }\n    console.log(\"selected accordion:\", details.value)\n  },\n})\n```\n\n### Disabling an accordion item\n\nTo disable a specific accordion item, pass the `disabled: true` property to the\n`getItemProps`, `getItemTriggerProps` and `getItemContentProps`.\n\nWhen an accordion item is disabled, it is skipped from keyboard navigation and\ncan't be interacted with.\n\n```jsx\n//...\n<div {...api.getItemProps({ value: \"item\", disabled: true })}>\n  <h3>\n    <button {...api.getItemTriggerProps({ value: \"item\", disabled: true })}>\n      Trigger\n    </button>\n  </h3>\n  <div {...api.getItemContentProps({ value: \"item\", disabled: true })}>\n    Content\n  </div>\n</div>\n//...\n```\n\nYou can also disable the entire accordion items by passing `disabled` to the\nmachine's context.\n\n```jsx {2}\nconst service = useMachine(accordion.machine, {\n  disabled: true,\n})\n```\n\n## Styling guide\n\nEarlier, we mentioned that each accordion part has a `data-part` attribute added\nto them to select and style them in the DOM.\n\n### Open and closed state\n\nWhen an accordion item is expanded or collapsed, a `data-state` attribute is set\non the item, trigger and content elements. This attribute is removed when it is\nclosed.\n\n```css\n[data-part=\"item\"][data-state=\"open|closed\"] {\n  /* styles for the item is open or closed state */\n}\n\n[data-part=\"item-trigger\"][data-state=\"open|closed\"] {\n  /* styles for the item is open or closed state */\n}\n\n[data-part=\"item-content\"][data-state=\"open|closed\"] {\n  /* styles for the item is open or closed state */\n}\n```\n\n### Focused state\n\nWhen an accordion item's trigger is focused, a `data-focus` attribute is set on\nthe item and content.\n\n```css\n[data-part=\"item\"][data-focus] {\n  /* styles for the item's focus state */\n}\n\n[data-part=\"item-trigger\"]:focus {\n  /* styles for the trigger's focus state */\n}\n\n[data-part=\"item-content\"][data-focus] {\n  /* styles for the content's focus state */\n}\n```\n\n## Creating Component\n\nCreate your accordion component by abstracting the machine into your own\ncomponent.\n\n### Usage\n\n```tsx\nimport { Accordion } from \"./your-accordion\"\n\nfunction Demo() {\n  return (\n    <Accordion\n      defaultValue={[\"1\"]}\n      items={[\n        { value: \"1\", title: \"Title 1\", content: \"Content 1\" },\n        { value: \"2\", title: \"Title 2\", content: \"Content 2\" },\n      ]}\n    />\n  )\n}\n```\n\n### Implementation\n\nUse the the `splitProps` utility to separate the machine's props from the\ncomponent's props.\n\n```tsx\nimport * as accordion from \"@zag-js/accordion\"\nimport { useMachine, normalizeProps } from \"@zag-js/react\"\nimport { useId } from \"react\"\n\ninterface Item {\n  value: string\n  title: React.ReactNode\n  content: React.ReactNode\n}\n\nexport interface AccordionProps extends Omit<accordion.Props, \"id\"> {\n  items: Item[]\n}\n\nexport function Accordion(props: AccordionProps) {\n  const [machineProps, localProps] = accordion.splitProps(props)\n\n  const service = useMachine(accordion.machine, {\n    id: useId(),\n    ...machineProps,\n  })\n\n  const api = accordion.connect(service, normalizeProps)\n\n  return (\n    <div {...api.getRootProps()}>\n      {localProps.items.map((item) => (\n        <div {...api.getItemProps({ value: item.value })}>\n          <h3>\n            <button {...api.getItemTriggerProps({ value: item.value })}>\n              {item.title}\n            </button>\n          </h3>\n          <div {...api.getItemContentProps({ value: item.value })}>\n            {item.content}\n          </div>\n        </div>\n      ))}\n    </div>\n  )\n}\n```\n\n## Methods and Properties\n\nThe accordion's `api` exposes the following methods and properties:\n\n### Machine Context\n\nThe accordion machine exposes the following context properties:\n\n**`ids`**\nType: `Partial<{ root: string; item: (value: string) => string; itemContent: (value: string) => string; itemTrigger: (value: string) => string; }>`\nDescription: The ids of the elements in the accordion. Useful for composition.\n\n**`multiple`**\nType: `boolean`\nDescription: Whether multiple accordion items can be expanded at the same time.\n\n**`collapsible`**\nType: `boolean`\nDescription: Whether an accordion item can be closed after it has been expanded.\n\n**`value`**\nType: `string[]`\nDescription: The controlled value of the expanded accordion items.\n\n**`defaultValue`**\nType: `string[]`\nDescription: The initial value of the expanded accordion items.\nUse when you don't need to control the value of the accordion.\n\n**`disabled`**\nType: `boolean`\nDescription: Whether the accordion items are disabled\n\n**`onValueChange`**\nType: `(details: ValueChangeDetails) => void`\nDescription: The callback fired when the state of expanded/collapsed accordion items changes.\n\n**`onFocusChange`**\nType: `(details: FocusChangeDetails) => void`\nDescription: The callback fired when the focused accordion item changes.\n\n**`orientation`**\nType: `\"horizontal\" | \"vertical\"`\nDescription: The orientation of the accordion items.\n\n**`dir`**\nType: `\"ltr\" | \"rtl\"`\nDescription: The document's text/writing direction.\n\n**`id`**\nType: `string`\nDescription: The unique identifier of the machine.\n\n**`getRootNode`**\nType: `() => ShadowRoot | Node | Document`\nDescription: A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.\n\n### Machine API\n\nThe accordion `api` exposes the following methods:\n\n**`focusedValue`**\nType: `string`\nDescription: The value of the focused accordion item.\n\n**`value`**\nType: `string[]`\nDescription: The value of the accordion\n\n**`setValue`**\nType: `(value: string[]) => void`\nDescription: Sets the value of the accordion\n\n**`getItemState`**\nType: `(props: ItemProps) => ItemState`\nDescription: Returns the state of an accordion item.\n\n### Data Attributes\n\n**`Root`**\n\n**`data-scope`**: accordion\n**`data-part`**: root\n**`data-orientation`**: The orientation of the accordion\n\n**`Item`**\n\n**`data-scope`**: accordion\n**`data-part`**: item\n**`data-state`**: \"open\" | \"closed\"\n**`data-focus`**: Present when focused\n**`data-disabled`**: Present when disabled\n**`data-orientation`**: The orientation of the item\n\n**`ItemContent`**\n\n**`data-scope`**: accordion\n**`data-part`**: item-content\n**`data-state`**: \"open\" | \"closed\"\n**`data-disabled`**: Present when disabled\n**`data-focus`**: Present when focused\n**`data-orientation`**: The orientation of the item\n\n**`ItemIndicator`**\n\n**`data-scope`**: accordion\n**`data-part`**: item-indicator\n**`data-state`**: \"open\" | \"closed\"\n**`data-disabled`**: Present when disabled\n**`data-focus`**: Present when focused\n**`data-orientation`**: The orientation of the item\n\n**`ItemTrigger`**\n\n**`data-scope`**: accordion\n**`data-part`**: item-trigger\n**`data-orientation`**: The orientation of the item\n**`data-state`**: \"open\" | \"closed\"\n\n## Accessibility\n\n### Keyboard Interactions\n\n**`Space`**\nDescription: When focus is on an trigger of a collapsed item, the item is expanded\n\n**`Enter`**\nDescription: When focus is on an trigger of a collapsed section, expands the section.\n\n**`Tab`**\nDescription: Moves focus to the next focusable element\n\n**`Shift + Tab`**\nDescription: Moves focus to the previous focusable element\n\n**`ArrowDown`**\nDescription: Moves focus to the next trigger\n\n**`ArrowUp`**\nDescription: Moves focus to the previous trigger.\n\n**`Home`**\nDescription: When focus is on an trigger, moves focus to the first trigger.\n\n**`End`**\nDescription: When focus is on an trigger, moves focus to the last trigger.","package":"@zag-js/accordion","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/components/accordion.mdx"}