Components

Accordion

Vertically stacked set of interactive headings that each reveal a section of content.

Category: Layout — Pattern: Base UI Accordion

Dependency: @base-ui-components/react/accordion

Preview

Loading preview...
import {
  Accordion,
  AccordionItem,
  AccordionHeader,
  AccordionTrigger,
  AccordionContent,
} from "@hareru/ui"

<Accordion defaultValue={["item-1"]}>
  <AccordionItem value="item-1">
    <AccordionHeader>
      <AccordionTrigger>What is Hareru UI?</AccordionTrigger>
    </AccordionHeader>
    <AccordionContent>
      <p>A semantic design system built for agents.</p>
    </AccordionContent>
  </AccordionItem>
  <AccordionItem value="item-2">
    <AccordionHeader>
      <AccordionTrigger>How do I install it?</AccordionTrigger>
    </AccordionHeader>
    <AccordionContent>
      <p>Run <code>npm install @hareru/tokens @hareru/ui</code>.</p>
    </AccordionContent>
  </AccordionItem>
</Accordion>

Import

import {
  Accordion,
  AccordionItem,
  AccordionHeader,
  AccordionTrigger,
  AccordionContent,
} from "@hareru/ui"

Exports

NameTypeDescription
AccordionComponentRoot accordion context; accepts type, value, defaultValue, onValueChange, disabled, and orientation
AccordionItemComponentIndividual accordion section; requires a value prop
AccordionHeaderComponentHeading element wrapping the trigger; maps to <h3> by default
AccordionTriggerComponentButton that toggles the panel; shows open/close indicator
AccordionContentComponentPanel that is shown or hidden based on the item's open state

Key Props

Accordion

PropTypeDefaultDescription
type'single' | 'multiple''multiple'Whether one or multiple panels can be open simultaneously
defaultValue(string | number)[][]Initial open items (uncontrolled)
value(string | number)[]Controlled open items
onValueChange(value: (string | number)[]) => voidCallback when open items change
disabledbooleanfalseDisables all items
orientation'horizontal' | 'vertical''vertical'Keyboard navigation orientation

AccordionItem Props

PropTypeDefaultDescription
valuestring | numberRequired. Unique identifier for this item
disabledbooleanfalseDisables this item independently of the root
onOpenChange(open: boolean) => voidCallback when this item's open state changes

Structure

  • AccordionItem [item] (expected) ×N
    • AccordionHeader [container] (expected)
      • AccordionTrigger [trigger] (expected)
    • AccordionContent [content] (expected)

(expected) = recommended in canonical composition, not runtime-required.

States

StateTypeValuesDefaultCSS Reflection
disabledboolean

Accessibility

  • Roles: region
  • ARIA attributes: aria-expanded, aria-controls
  • Keyboard:
    • Enter or Space to toggle
    • Arrow Up/Down to navigate items
  • Notes: WAI-ARIA Accordion pattern with keyboard navigation provided by Base UI.

Usage

import {
  Accordion,
  AccordionItem,
  AccordionHeader,
  AccordionTrigger,
  AccordionContent,
} from "@hareru/ui"

// Basic — multiple panels open at once (default)
<Accordion defaultValue={["item-1"]}>
  <AccordionItem value="item-1">
    <AccordionHeader>
      <AccordionTrigger>What is Hareru UI?</AccordionTrigger>
    </AccordionHeader>
    <AccordionContent>
      <p>A semantic design system built for agents.</p>
    </AccordionContent>
  </AccordionItem>
  <AccordionItem value="item-2">
    <AccordionHeader>
      <AccordionTrigger>How do I install it?</AccordionTrigger>
    </AccordionHeader>
    <AccordionContent>
      <p>Run <code>npm install @hareru/tokens @hareru/ui</code>.</p>
    </AccordionContent>
  </AccordionItem>
</Accordion>

// Single — only one panel open at a time
<Accordion type="single" defaultValue={["item-1"]}>
  <AccordionItem value="item-1">
    <AccordionHeader>
      <AccordionTrigger>Section 1</AccordionTrigger>
    </AccordionHeader>
    <AccordionContent><p>Content 1</p></AccordionContent>
  </AccordionItem>
  <AccordionItem value="item-2">
    <AccordionHeader>
      <AccordionTrigger>Section 2</AccordionTrigger>
    </AccordionHeader>
    <AccordionContent><p>Content 2</p></AccordionContent>
  </AccordionItem>
</Accordion>

// Disabled item
<Accordion>
  <AccordionItem value="item-1">
    <AccordionHeader>
      <AccordionTrigger>Available</AccordionTrigger>
    </AccordionHeader>
    <AccordionContent><p>This panel can be opened.</p></AccordionContent>
  </AccordionItem>
  <AccordionItem value="item-2" disabled>
    <AccordionHeader>
      <AccordionTrigger>Disabled</AccordionTrigger>
    </AccordionHeader>
    <AccordionContent><p>This panel cannot be opened.</p></AccordionContent>
  </AccordionItem>
</Accordion>

// Controlled
<Accordion value={openItems} onValueChange={setOpenItems}>
  <AccordionItem value="item-1">
    <AccordionHeader>
      <AccordionTrigger>Controlled Section</AccordionTrigger>
    </AccordionHeader>
    <AccordionContent><p>Open state managed externally.</p></AccordionContent>
  </AccordionItem>
</Accordion>

Notes

  • Unlike Collapsible (a single show/hide section), Accordion manages a list of items and coordinates their open states under one root.
  • defaultValue and value are always arrays, even in type="single" mode (e.g. defaultValue={["item-1"]}).
  • AccordionContent animates open/close via CSS animations on the [data-open] and [data-ending-style] attributes.
  • AccordionItem, AccordionHeader, and AccordionContent expose [data-open] for CSS targeting. Note that AccordionTrigger uses [data-panel-open] instead.
  • With type="single", opening one item automatically closes the previously open item.

On this page