Skip to content

Navigation

Accordion

A stack of expandable answers.

When to use it: Use it to hide optional detail while keeping headings visible.

On this page

Example

Loading example…
Accordion.tsxtsx
import {
  Accordion,
  AccordionHeader,
  AccordionItem,
  AccordionPanel,
  AccordionTrigger,
} from "@comp0/react";
import { ChevronDownIcon } from "@heroicons/react/16/solid";

export function Example() {
  return (
    <Accordion
      as="div"
      className="divide-y divide-zinc-950/10 rounded border border-zinc-950/10 dark:divide-white/10 dark:border-white/10"
      defaultValue="shipping"
    >
      <AccordionItem value="shipping">
        <AccordionHeader className="m-0">
          <AccordionTrigger className="group flex w-full items-center justify-between px-3 py-2.5 text-left text-base text-zinc-900 select-none sm:py-2 sm:text-sm dark:text-zinc-100">
            Shipping{" "}
            <ChevronDownIcon
              className="size-4 text-zinc-400 transition-transform duration-150 ease-out group-data-open:rotate-180 motion-reduce:transition-none"
              aria-hidden="true"
            />
          </AccordionTrigger>
        </AccordionHeader>
        <AccordionPanel className="docs-accordion-panel grid grid-rows-[1fr] overflow-hidden transition-[grid-template-rows] duration-150 ease-out motion-reduce:transition-none [&[hidden]]:grid-rows-[0fr]">
          <div className="min-h-0 overflow-hidden">
            <div className="px-3 pb-3 text-base text-zinc-600 sm:text-sm dark:text-zinc-400">
              Orders leave our warehouse in two business days.
            </div>
          </div>
        </AccordionPanel>
      </AccordionItem>
      <AccordionItem value="returns">
        <AccordionHeader className="m-0">
          <AccordionTrigger className="group flex w-full items-center justify-between px-3 py-2.5 text-left text-base text-zinc-900 select-none sm:py-2 sm:text-sm dark:text-zinc-100">
            Returns{" "}
            <ChevronDownIcon
              className="size-4 text-zinc-400 transition-transform duration-150 ease-out group-data-open:rotate-180 motion-reduce:transition-none"
              aria-hidden="true"
            />
          </AccordionTrigger>
        </AccordionHeader>
        <AccordionPanel className="docs-accordion-panel grid grid-rows-[1fr] overflow-hidden transition-[grid-template-rows] duration-150 ease-out motion-reduce:transition-none [&[hidden]]:grid-rows-[0fr]">
          <div className="min-h-0 overflow-hidden">
            <div className="px-3 pb-3 text-base text-zinc-600 sm:text-sm dark:text-zinc-400">
              Returns are accepted within 30 days.
            </div>
          </div>
        </AccordionPanel>
      </AccordionItem>
    </Accordion>
  );
}

Anatomy

Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.

A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.

  1. Accordion

    Open-item state provider. Does not add a DOM element.

  2. AccordionItem

    Owns an item wrapper. Owns a DOM element.

  3. AccordionHeader

    Heading wrapper. Owns a DOM element.

  4. AccordionTrigger

    Native button that opens its panel. Owns a DOM element.

  5. AccordionPanel

    Revealed region. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Start Accordion with one AccordionItem and value.

  2. 2

    Add the supporting parts

    Put Header and Trigger before the matching Panel.

  3. 3

    Make the behavior clear

    Use defaultValue for the item that should begin open.

    Exampletsx
    <Accordion defaultValue="one">
      <AccordionItem value="one">
        <AccordionHeader>
          <AccordionTrigger>Details</AccordionTrigger>
        </AccordionHeader>
        <AccordionPanel>More information.</AccordionPanel>
      </AccordionItem>
    </Accordion>;

Keyboard

↓
Moves to next trigger.
↑
Moves to previous trigger.
Home
Moves to the first trigger.
End
Moves to the last trigger.
↵
Toggles the item.
Space
Toggles the item.

Forms and accessibility

No native form behavior.

Accessibility checklist

  • Write trigger headings that describe the hidden content.
  • Keep the expanded state visually clear.
  • Do not hide important error messages inside a collapsed item.

API reference

Importtsx
import { Accordion, AccordionHeader, AccordionItem, AccordionPanel, AccordionTrigger } from "@comp0/react";

Accordion

Context only

Open-item state provider.

PropTypeDescription
type"single" | "multiple"How many items may stay open.
valuestring | string[]Controlled open items.
defaultValuestring | string[]Initial open items.
onChange(value) => voidReceives the next open items.
collapsiblebooleanAllows closing the last open item.
asElementTypeRenders a wrapper element that carries the root's data attributes; without it the root renders no DOM and DOM props are a type error.

AccordionItem

DOM element

Owns an item wrapper.

PropTypeDescription
valuestringIdentity used by the root’s open state.
disabledbooleanDisables the item.

AccordionHeader

DOM element

Heading wrapper.

PropTypeDescription
level1 | 2 | 3 | 4 | 5 | 6Heading element to render; defaults to h3.

AccordionTrigger

DOM element

Native button that opens its panel.

PropTypeDescription
disabledbooleanDisables this trigger on top of the item's disabled state.

AccordionPanel

DOM element

Revealed region.

PropTypeDescription
role"region" | "group"Use group when many panels would flood landmarks.

Style hooks

Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.

AccordionItem

Style hookMeaning
[data-open]The item is expanded.
[data-disabled]The trigger is disabled.

AccordionTrigger

Style hookMeaning
[data-open]The item is expanded.
[data-disabled]The trigger is disabled.

AccordionPanel

Style hookMeaning
[data-open]The item is expanded.

Keep exploring