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 ·
Installation
bunx --bun shadcn@latest add @dga/accordionUsage
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
valueidentifies 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.
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.
Accessibility
| Key | Action |
|---|---|
| Tab | Moves focus to the next heading. |
| Enter | Opens or closes the focused section. |
| Space | Opens or closes the focused section. |
- Built on Base UI Accordion: each heading is a
<button>witharia-expandedandaria-controls, inside a heading element; the panel is aregionlabelled 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`.
| Prop | Type | Default |
|---|---|---|
"sm" | "md" | "lg"Header padding: `sm` 8px, `md` 12px, `lg` 16px (DGA). | "lg" | |
| ||
"trailing" | "leading"Where the chevron sits: `trailing` (default) or `leading`. | "trailing" | |
| ||
booleanThe lines stop 16px short of the edges. | false | |
| ||
booleanWhether 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[]) => voidEvent 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.
| Prop | Type | Default |
|---|---|---|
stringA 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 | |
| ||
booleanWhether 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]andhtml[lang=ar](twelve rules). Logical padding (psandpe) needs none. - Flush is a 16px margin on each side of the line; DGA draws it with a
border-imagegradient at 16px and 382px, which only fits one width. - A disabled section uses
text-default-disabledinstead ofneutral-300with!important.
| Change | Reason |
|---|---|
Accordion: RTL padding, flush and disabled | The CSS needs twelve rules where logical properties need none, and the gradient hard-codes a 382px width. |
Contrast
60 pairs checked · all pass WCAG 2.1 AAShow 10 statesHide
| Variant / state | Light | Dark |
|---|---|---|
| heading | 17.31:1 AAA | 15.87:1 AAA |
| chevron | 17.31:1 3:1 | 15.87:1 3:1 |
| panel text | 9.73:1 AAA | 12.04:1 AAA |
| focus ring | 17.31:1 3:1 | 17.49:1 3:1 |
| heading / hovered | 16.44:1 AAA | 9.59:1 AAA |
| chevron / hovered | 16.44:1 3:1 | 9.59:1 3:1 |
| focus ring / hovered | 16.44:1 3:1 | 10.57:1 3:1 |
| heading / pressed | 14.61:1 AAA | 6.95:1 AA |
| chevron / pressed | 14.61:1 3:1 | 6.95:1 3:1 |
| focus ring / pressed | 14.61:1 3:1 | 7.66:1 3:1 |
Text needs 4.5:1, icons and focus rings 3:1. Disabled states are exempt. Full contrast report