Accordion
Introduction
Installation
Base UI components are all available as a single package.
npm install @base-ui-components/react
Once you have the package installed, import the component.
import { Accordion } from '@base-ui-components/react/accordion';Anatomy
Accordions are implemented using a collection of related components:
- <Accordion.Root />is a top-level component that wraps the other components.
- <Accordion.Item />is a component that wraps each section of content and it's associated- Trigger
- <Accordion.Trigger />is a button that toggles the open state of its associated- Item
- <Accordion.Header />is a heading (- h3by default) that wraps the- Trigger
- <Accordion.Panel />is the element that contains content in a- Item
<Accordion.Root>
  <Accordion.Item>
    <Accordion.Header>
      <Accordion.Trigger>Toggle one</Accordion.Trigger>
    </Accordion.Header>
    <Accordion.Panel>Panel one content</Accordion.Panel>
  </Accordion.Item>
  <Accordion.Item>
    <Accordion.Header>
      <Accordion.Trigger>Toggle two</Accordion.Trigger>
    </Accordion.Header>
    <Accordion.Panel>Panel two content</Accordion.Panel>
  </Accordion.Item>
</Accordion.Root>Value
Each Accordion.Item is represented by a value, which by default is its zero-based index by DOM position.
The first Item has an implicit value of 0, the second one Item a value of 1, and so on.
The open state of the accordion is represented an array holding the values of all open Items.
You can optionally specify a custom value prop on Item:
<Accordion.Root>
  <Accordion.Item value="one">
    <Accordion.Header>
      <Accordion.Trigger>Toggle one</Accordion.Trigger>
    </Accordion.Header>
    <Accordion.Panel>Panel one content</Accordion.Panel>
  </Accordion.Item>
  <Accordion.Item value="two">
    <Accordion.Header>
      <Accordion.Trigger>Toggle two</Accordion.Trigger>
    </Accordion.Header>
    <Accordion.Panel>Panel two content</Accordion.Panel>
  </Accordion.Item>
</Accordion.Root>Default value
When uncontrolled, use the defaultValue prop to set the initial state of the accordion:
<Accordion.Root defaultValue={[0]}>
  <Accordion.Item {/* `value={0}` by default */}>
    <Accordion.Header>
      <Accordion.Trigger>Toggle one</Accordion.Trigger>
    </Accordion.Header>
    <Accordion.Panel>Panel one content</Accordion.Panel>
  </Accordion.Item>
  <Accordion.Item {/* `value={1}` by default */}>
    <Accordion.Header>
      <Accordion.Trigger>Toggle two</Accordion.Trigger>
    </Accordion.Header>
    <Accordion.Panel>Panel two content</Accordion.Panel>
  </Accordion.Item>
</Accordion.Root>;
// with custom `value`s
<Accordion.Root defaultValue={['a']}>
  <Accordion.Item value="a">
    <Accordion.Header>
      <Accordion.Trigger>Toggle one</Accordion.Trigger>
    </Accordion.Header>
    <Accordion.Panel>Panel one content</Accordion.Panel>
  </Accordion.Item>
  <Accordion.Item value="b">
    <Accordion.Header>
      <Accordion.Trigger>Toggle two</Accordion.Trigger>
    </Accordion.Header>
    <Accordion.Panel>Panel two content</Accordion.Panel>
  </Accordion.Item>
</Accordion.Root>;Controlled
When controlled, pass the value and onValueChange props to Accordion.Root:
const [value, setValue] = React.useState(['a']);
return (
  <Accordion.Root value={value} onValueChange={setValue}>
    <Accordion.Item value="a">
      <Accordion.Header>
        <Accordion.Trigger>Toggle one</Accordion.Trigger>
      </Accordion.Header>
      <Accordion.Panel>Panel one content</Accordion.Panel>
    </Accordion.Item>
    <Accordion.Item value="b">
      <Accordion.Header>
        <Accordion.Trigger>Toggle two</Accordion.Trigger>
      </Accordion.Header>
      <Accordion.Panel>Panel two content</Accordion.Panel>
    </Accordion.Item>
  </Accordion.Root>
);Customization
Only one Item open at a time
By default, all accordion items can be opened at the same time. Use the openMultiple prop to only allow one open item at a time:
<Accordion.Root openMultiple={false}>{/* subcomponents */}</Accordion.Root>At least one Item remains open
Use controlled mode to always keep one Item open:
const [value, setValue] = React.useState([0]);
const handleValueChange = (newValue) => {
  if (newValue.length > 0) {
    setValue(newValue);
  }
};
return (
  <Accordion.Root value={value} onValueChange={handleValueChange}>
    {/* subcomponents */}
  </Accordion.Root>
);Horizontal
Use the orientation prop to configure a horizontal accordion. In a horizontal accordion, focus will move between Accordion.Triggers with the Right Arrow and Left Arrow keys, instead of Down/Up.
<Accordion.Root orientation="horizontal">{/* subcomponents */}</Accordion.Root>RTL
To change direction for right-to-left languages, place the accordion in DirectionProvider with the direction="rtl" prop to configure RTL behavior, and set the dir attribute accordingly in your HTML to affect styling:
<html dir="rtl">
  <body>
    <DirectionProvider direction="rtl">
      <Accordion.Root>{/* Subcomponents */}</Accordion.Root>
    </DirectionProvider>
  </body>
</html>When RTL, keyboard actions for horizontal accordions are reversed - Left Arrow moves focus to the next trigger and Right Arrow moves focus to the previous trigger.
Hidden state
<Accordion.Panel />s are unmounted from the DOM by default when they are closed. The keepMounted prop can be used to keep them mounted when closed, and instead rely on the hidden attribute to hide the content:
<Accordion.Root keepMounted>{/* accordion items */}</Accordion.Root>Alternatively keepMounted can be passed to Accordion.Panels directly to enable this for only one Item instead of the whole accordion.
Improving searchability of hidden content
This is not yet
supported in Safari and
Firefox as of August 2024 and will fall back to the default hidden behavior.
Content hidden by Accordion.Panel components can be made accessible only to a browser's find-in-page functionality with the hiddenUntilFound prop to improve searchability:
<Accordion.Root hiddenUntilFound>{/* subcomponents */}</Accordion.Root>When hiddenUntilFound is used, Accordion.Panels remain mounted even when closed, overriding the keepMounted prop on the root or the panel.
Alternatively hiddenUntilFound can be passed to Accordion.Panels directly to enable this for only one Item instead of the whole accordion.
We recommend using CSS animations for animated accordions that use this feature. Currently there is browser bug that does not highlight the found text inside elements that have a CSS transition applied.
This relies on the HTML hidden="until-found" attribute which only has partial browser support as of August 2024, but automatically falls back to the default hidden state in unsupported browsers.
Animations
Accordion uses Collapsible internally, and can be animated in a similar way.
Three states are available as data attributes to animate the Accordion.Panel:
- [data-open]-- openstate is- true.
- [data-starting-style]- the- hiddenattribute was just removed from the DOM and the panel element participates in page layout. The- data-starting-styleattribute will be removed 1 animation frame later.
- [data-ending-style]- the panel element is in the process of being hidden from the DOM, but is still mounted.
The component can be animate when opening or closing using either:
- CSS animations
- CSS transitions
- JavaScript animations
Styling
The Accordion.Panel element receives the following CSS variables about its dimensions, which can be used to style animations or transitions:
- --accordion-panel-height: Specifies the height of the- Panel.
- --accordion-panel-width: Specifies the width of the- Panel.
CSS Animations
CSS animations can be used with two declarations:
.AccordionPanel {
  overflow: hidden;
  animation: slideUp 300ms ease-in;
}
.AccordionPanel[data-open] {
  animation: slideDown 300ms ease-out;
}
@keyframes slideDown {
  from {
    height: 0;
  }
  to {
    height: var(--accordion-panel-height);
  }
}
@keyframes slideUp {
  from {
    height: var(--accordion-panel-height);
  }
  to {
    height: 0;
  }
}CSS Transitions
When using CSS transitions, styles for the Panel must be applied to three states:
- The exiting styles, placed on the base element class
- The open styles, placed on the base element class with [data-state="open"]
- The entering styles, placed on the base element class with [data-starting-style]
.AccordionPanel {
  overflow: hidden;
  /* The final styles once closed/exited  */
  height: 0;
  transition: height 300ms ease-in;
}
/* The final styles once opened/entered */
.AccordionPanel[data-open] {
  height: var(--accordion-panel-height);
  transition: height 300ms ease-out;
}
/* The initial styles when opening/entering */
.AccordionPanel[data-starting-style] {
  height: 0;
}JavaScript Animations
Use the keepMounted prop lets an external library control the mounting, for example framer-motion:
function App() {
  const [value, setValue] = useState([0]);
  return (
    <Accordion.Root value={value} onValueChange={setValue} keepMounted>
      <Accordion.Item>
        <Accordion.Header>
          <Accordion.Trigger>Toggle</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Panel
          render={
            <motion.div
              key="AccordionPanel"
              initial={false}
              animate={open ? 'open' : 'closed'}
              exit={!open ? 'open' : 'closed'}
              variants={{
                open: {
                  height: 'auto',
                  transition: { duration: 0.3, ease: 'ease-out' },
                },
                closed: {
                  height: 0,
                  transition: { duration: 0.3, ease: 'ease-in' },
                  transitionEnd: { display: 'revert-layer' },
                },
              }}
            />
          }
        >
          This is the content
        </Accordion.Panel>
      </Accordion.Item>
      {/* more accordion items */}
    </Accordion.Root>
  );
}API Reference
AccordionRoot
| Prop | Type | Default | Description | 
|---|---|---|---|
| className | union | Class names applied to the element or a function that returns them based on the component's state. | |
| defaultValue | array | The default value representing the currently open Accordion.ItemThis is the uncontrolled counterpart ofvalue. | |
| disabled | bool | false | If true, the component is disabled. | 
| bool | false | If true, setshidden="until-found"when closed. Accordion panels will remain mounted in the DOM when closed and overrideskeepMounted. Iffalse, setshiddenwhen closed. | |
| keepMounted | bool | false | If true, accordion panels remains mounted when closed and is instead hidden using thehiddenattribute. Iffalse, accordion panels are unmounted when closed. | 
| loop | bool | true | If true, focus will loop when moving focus betweenTriggers using the arrow keys. | 
| onValueChange | func | Callback fired when an Accordion section is opened or closed. The value representing the involved section is provided as an argument. | |
| openMultiple | bool | true | Whether multiple Accordion sections can be opened at the same time. | 
| orientation | enum | 'vertical' | The orientation of the accordion. | 
| render | union | A function to customize rendering of the component. | |
| value | array | The value of the currently open Accordion.ItemThis is the controlled counterpart ofdefaultValue. | 
AccordionItem
| Prop | Type | Default | Description | 
|---|---|---|---|
| className | union | Class names applied to the element or a function that returns them based on the component's state. | |
| disabled | bool | false | If true, the component is disabled. | 
| onOpenChange | func | Callback fired when the Collapsible is opened or closed. | |
| render | union | A function to customize rendering of the component. | 
AccordionHeader
| Prop | Type | Default | Description | 
|---|---|---|---|
| className | union | Class names applied to the element or a function that returns them based on the component's state. | |
| render | union | A function to customize rendering of the component. | 
AccordionTrigger
| Prop | Type | Default | Description | 
|---|---|---|---|
| className | union | Class names applied to the element or a function that returns them based on the component's state. | |
| render | union | A function to customize rendering of the component. | 
AccordionPanel
| Prop | Type | Default | Description | 
|---|---|---|---|
| className | union | Class names applied to the element or a function that returns them based on the component's state. | |
| bool | false | If true, setshidden="until-found"when closed. Accordion panels will remain mounted in the DOM when closed and overrideskeepMounted. Iffalse, setshiddenwhen closed. | |
| keepMounted | bool | false | If true, accordion panels remains mounted when closed and is instead hidden using thehiddenattribute. Iffalse, accordion panels are unmounted when closed. | 
| render | union | A function to customize rendering of the component. |