Accordion
Stacked headings that each reveal a panel, with height motion you can reverse mid-way and panels that stay searchable while closed.
pnpm dlx shadcn@latest add https://hextaui.com/r/accordion.jsonAdds the component, the HextaUI theme tokens and any HextaUI components it depends on.
Add the theme tokens to your global CSS, if you haven’t yet.
Install the dependencies.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnCopy and paste the following code into your project.
components/ui/accordion.tsx Update the import paths to match your project setup.
Items share one bordered surface, with the outer corners rounded.
Each item is its own card.
No borders. Triggers get a soft fill on hover and when open.
Set multiple to let more than one item stay open.
Disable a single item with disabled on <AccordionItem />, or the whole accordion on the root.
Pass value and onValueChange to keep the open items in your own state.
Pass any element to icon. Style its open state with group-data-panel-open/accordion-trigger.
Icons before the label are sized and aligned for you. icon={null} removes the chevron.
Long titles wrap while the icon stays on the first line. Closed panels stay searchable, so Cmd/Ctrl+F for “retention” opens this one.
An inner accordion keeps its own variant, focus styles and arrow-key navigation.
Content, icons and the open motion follow the reading direction.
| Key | Action |
|---|---|
| EnterSpace | Opens or closes the focused item. |
| ↓ | Moves focus to the next trigger. |
| ↑ | Moves focus to the previous trigger. |
| Home | Moves focus to the first trigger. |
| End | Moves focus to the last trigger. |
| Tab | Moves focus into the open panel, then on to the next trigger. |
Built on the Base UI accordion. Every part accepts the props of the primitive it wraps.
| Prop | Type | Default |
|---|---|---|
variant | "default" | "outline" | "separated" | "ghost" | "default" |
multipleAllow more than one item to be open. | boolean | false |
value | Value[] | – |
defaultValue | Value[] | – |
onValueChange | (value: Value[], details) => void | – |
disabled | boolean | false |
hiddenUntilFoundKeep closed panels findable with the browser’s page search. | boolean | true |
keepMountedIgnored while hiddenUntilFound is on. | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribute | Description |
|---|---|
data-slot="accordion" | Target the root in CSS. |
data-variant | The current variant. |
data-disabled | Present when the accordion is disabled. |
| Prop | Type | Default |
|---|---|---|
valueGenerated automatically when omitted. | Value | – |
disabled | boolean | false |
onOpenChange | (open: boolean, details) => void | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribute | Description |
|---|---|
data-slot="accordion-item" | Target items in CSS. |
data-open | Present when the item is open. |
data-disabled | Present when the item is disabled. |
data-index | The item’s position, starting at 0. |
| Prop | Type | Default |
|---|---|---|
iconnull removes the icon. | ReactNode | null | <IconChevronDown /> |
render | ReactElement | (props, state) => ReactElement | <button> |
| Attribute | Description |
|---|---|
data-slot="accordion-trigger" | Target triggers in CSS. |
data-panel-open | Present when its panel is open. Style the icon with group-data-panel-open/accordion-trigger. |
data-disabled | Present when the item is disabled. |
| Prop | Type | Default |
|---|---|---|
classNameApplied to the inner wrapper, so padding never fights the height animation. | string | – |
keepMounted | boolean | false |
hiddenUntilFound | boolean | – |
| Attribute | Description |
|---|---|
data-slot="accordion-content" | Target panels in CSS. |
data-open | Present when the panel is open. |
data-starting-style | Present while the panel animates in. |
data-ending-style | Present while the panel animates out. |
data-settled | Present once the panel is fully open. It stops clipping then, so focus rings inside a nested accordion show in full. |
--accordion-panel-height | The panel’s measured height, used for the height animation. |
- Aspect ratioA box that holds its shape before media loads, shimmers while loading, fades the media in and falls back when it fails.
- CarouselNative scroll-snap slides with momentum on touch, mouse dragging, arrow keys, dots, thumbnails and an autoplay that pauses when it should.
- CollapsibleA panel that shows and hides with height motion you can reverse mid-way, without jumping the layout.
- ResizablePanels you can drag apart, with a quiet divider that wakes up on hover, sizes that glide on reset or collapse, and layouts that persist.
- Scroll areaNative scrolling with a minimal scrollbar, edges that fade only where there’s more to see, and an optional peek that cuts the last item in half.
- SeparatorA hairline that divides content horizontally or vertically, with an optional label and a decorative mode for purely visual lines.