Skip to content

Accordion

Shows and hides sections of content under their headings. Three sizes, a leading or trailing chevron, flush, and single or multiple open.

Version 0.4.1 ·

Accordion

Installation

bunx --bun shadcn@latest add @dga/accordion

Usage

page.tsx
tsx
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion";

export function ServiceFaq() {
  return (
    <Accordion defaultValue={["eligibility"]}>
      <AccordionItem value="eligibility">
        <AccordionTrigger>Who can apply?</AccordionTrigger>
        <AccordionContent>Citizens and residents with a valid ID.</AccordionContent>
      </AccordionItem>
      <AccordionItem value="time">
        <AccordionTrigger>How long does processing take?</AccordionTrigger>
        <AccordionContent>Most requests are completed within 5 working days.</AccordionContent>
      </AccordionItem>
    </Accordion>
  );
}

Use an Accordion for content people scan by heading and open only in part: questions and answers, the sections of a long form. Do not hide what everyone must read. By default one section is open at a time; set multiple to let people open several.

Anatomy

  • Item: one section, with a 1px line above it. The value identifies it.
  • Trigger (a <button> in a heading): Text md, Semibold, with a chevron that turns when the section is open.
  • Panel (role="region"): the content. It animates its height.

Examples

Sizes, leading and flush

size sets the header padding: sm 8px, md 12px, lg 16px. iconPosition="leading" puts the chevron first. flush keeps the lines 16px from the edges. multiple lets several sections stay open.

Sizes, leading and flush

RTL

The chevron sits on the end side (the left in Arabic), or the start side with iconPosition="leading". The panel text is indented with logical padding so it lines up with the heading text. No [dir=rtl] overrides are needed.

LTR (English)
RTL (Arabic)

Accessibility

KeyAction
TabMoves focus to the next heading.
EnterOpens or closes the focused section.
SpaceOpens or closes the focused section.
  • Built on Base UI Accordion: each heading is a <button> with aria-expanded and aria-controls, inside a heading element; the panel is a region labelled by it. A closed panel is hidden from screen readers. As the WAI-ARIA pattern asks, Tab, Enter and Space are all that is needed.
  • The open state is shown by the chevron turning and by the panel itself, not by colour. Focus is a 2px outline inside the heading.
  • Text is 4.5:1 and the chevron 3:1 or better in every state, light and dark. A disabled section cannot be opened.
  • The panel opens and closes by animating its height; with reduced motion it opens at once.

API Reference

Accordion

Shows and hides sections of content under their headings (DGA: Accordion). Each heading is a button: Tab moves between headings and Enter or Space opens or closes the section. One section is open at a time unless you set `multiple`.

Accordion props
PropTypeDefault
"sm" | "md" | "lg"

Header padding: `sm` 8px, `md` 12px, `lg` 16px (DGA).

"lg"
"trailing" | "leading"

Where the chevron sits: `trailing` (default) or `leading`.

"trailing"
boolean

The lines stop 16px short of the edges.

false
boolean

Whether multiple items can be open at the same time.

No default
string[]

The controlled value of the item(s) that should be expanded. To render an uncontrolled accordion, use the `defaultValue` prop instead.

No default
string[]

The uncontrolled value of the item(s) that should be initially expanded. To render a controlled accordion, use the `value` prop instead.

No default
(value: string[]) => void

Event handler called when an accordion item is expanded or collapsed. Provides the new value as an argument.

No default

Also accepts every prop of the Base UI Accordion (opens in a new tab).

AccordionContent

The content of a section. It animates its height and is hidden from screen readers while closed.

Also accepts every prop of the Base UI Accordion (opens in a new tab).

AccordionItem

One section: a heading and its panel. Give it a `value` to control which are open.

AccordionItem props
PropTypeDefault
string

A unique value that identifies this accordion item. If no value is provided, a unique ID will be generated automatically. Use when controlling the accordion programmatically, or to set an initial open state.

No default
boolean

Whether the component should ignore user interaction.

No default

Also accepts every prop of the Base UI Accordion (opens in a new tab).

AccordionTrigger

The heading button. It shows a chevron that turns when the section is open.

Also accepts every prop of the Base UI Accordion (opens in a new tab).

Deviations from DGA

  • The DGA CSS repeats every body-padding rule for [dir=rtl] and html[lang=ar] (twelve rules). Logical padding (ps and pe) needs none.
  • Flush is a 16px margin on each side of the line; DGA draws it with a border-image gradient at 16px and 382px, which only fits one width.
  • A disabled section uses text-default-disabled instead of neutral-300 with !important.
ChangeReason
Accordion: RTL padding, flush and disabledThe CSS needs twelve rules where logical properties need none, and the gradient hard-codes a 382px width.

View all 1 deviations for this component

Contrast

60 pairs checked · all pass WCAG 2.1 AAShow 10 states
Variant / stateLightDark
heading17.31:1 AAA15.87:1 AAA
chevron17.31:1 3:115.87:1 3:1
panel text9.73:1 AAA12.04:1 AAA
focus ring17.31:1 3:117.49:1 3:1
heading / hovered16.44:1 AAA9.59:1 AAA
chevron / hovered16.44:1 3:19.59:1 3:1
focus ring / hovered16.44:1 3:110.57:1 3:1
heading / pressed14.61:1 AAA6.95:1 AA
chevron / pressed14.61:1 3:16.95:1 3:1
focus ring / pressed14.61:1 3:17.66:1 3:1

Text needs 4.5:1, icons and focus rings 3:1. Disabled states are exempt. Full contrast report