Accordion
A stack of sections separated by hairlines that expand one or several at a time.
npx prodular-ui add accordionDefault
One open at a time. The first item opens by default.
You pay for active seats at the start of each cycle. Seats added mid cycle are prorated to the day and appear on the next invoice.
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger,} from "@/components/ui/accordion"
const faqs = [ { q: "How are seats billed?", a: "You pay for active seats at the start of each cycle. Seats added mid cycle are prorated to the day and appear on the next invoice.", }, { q: "Can I switch from monthly to annual billing?", a: "Yes. Annual billing saves 18% and starts the day you switch. Unused time on the monthly plan is credited to your account.", }, { q: "What happens when a payment fails?", a: "We retry three times over seven days and email the billing contacts each time. The workspace stays active until the last retry.", }, { q: "Do you offer invoicing by bank transfer?", a: "Bank transfer is available on annual plans over $10,000. Contact billing@halden.io to set it up.", },]
export default function AccordionDefault() { return ( <Accordion defaultValue={["seats"]} className="max-w-lg"> {faqs.map((f, i) => ( <AccordionItem key={f.q} value={i === 0 ? "seats" : f.q}> <AccordionTrigger>{f.q}</AccordionTrigger> <AccordionContent>{f.a}</AccordionContent> </AccordionItem> ))} </Accordion> )}In a card
multiple lets several sections stay open. Icons and metadata sit inside the trigger.
import { DatabaseIcon, GlobeIcon, ShieldCheckIcon } from "lucide-react"
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger,} from "@/components/ui/accordion"import { Badge } from "@/components/ui/badge"import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
const sections = [ { value: "residency", icon: GlobeIcon, title: "Data residency", meta: "EU (Frankfurt)", body: "Customer data, backups and logs are stored in eu-central-1. Moving regions requires a migration window of about 2 hours.", }, { value: "retention", icon: DatabaseIcon, title: "Retention", meta: "400 days", body: "Events older than 400 days are deleted every night at 03:00 UTC. Exports you downloaded are not affected.", }, { value: "sso", icon: ShieldCheckIcon, title: "Single sign-on", meta: "Okta", body: "SAML is enforced for halden.io addresses. Guests outside the domain still sign in with email and a one time code.", },]
export default function AccordionCard() { return ( <Card className="w-full max-w-lg"> <CardHeader> <CardTitle>Security and compliance</CardTitle> <CardDescription>Workspace defaults set by your admins.</CardDescription> </CardHeader> <CardContent> <Accordion multiple className="border-t"> {sections.map(({ value, icon: Icon, title, meta, body }) => ( <AccordionItem key={value} value={value}> <AccordionTrigger> <span className="flex flex-1 items-center gap-2.5"> <Icon /> {title} </span> <Badge size="sm" variant="secondary"> {meta} </Badge> </AccordionTrigger> <AccordionContent className="pl-6.5">{body}</AccordionContent> </AccordionItem> ))} </Accordion> </CardContent> </Card> )}Anatomy
<Accordion defaultValue={["seats"]}> <AccordionItem value="seats"> <AccordionTrigger>How are seats billed?</AccordionTrigger> <AccordionContent>...</AccordionContent> </AccordionItem></Accordion>Guidance
Use it when
- FAQs and help content where people read one answer at a time.
- Long settings or details that most people do not need to see at once.
Avoid
- Hiding content people need to compare side by side. Show it in a table.
- Nesting accordions inside accordions.
- A single item. Use Collapsible instead.
Rules for AI agents
Published in llms-full.txt, the registry and the MCP server, so coding agents follow them when they build with this component.
- Give every AccordionItem a unique value. Pass defaultValue as an array of values to open items on load.
- Pass multiple on Accordion when sections are independent, such as settings. Leave it off for FAQs.
- Write triggers as questions or nouns in sentence case. Keep them to one line.
- Do not add borders or backgrounds to items. Items are separated by hairlines already.
- Put the accordion directly in CardContent when it lives in a card. Add border-t on Accordion if it follows other content.
- Use variant="section" for inspector and property sections instead of restyling AccordionTrigger.
- className on AccordionContent styles the content wrapper, text color included; use panelClassName for the animated panel itself.
API
Accordion
| Prop | Type | Default | Description |
|---|---|---|---|
| multiple | boolean | false | Allows more than one item to be open. |
| defaultValue | any[] | Values of the items open on first render. | |
| variant | "default" | "section" | "default" | section gives compact headers for inspector panels and property editors. |
AccordionItem
| Prop | Type | Default | Description |
|---|---|---|---|
| value | any | Identifies the item. | |
| disabled | boolean | false | Blocks opening the item. |
AccordionContent
| Prop | Type | Default | Description |
|---|---|---|---|
| panelClassName | string | Classes for the animated panel. className styles the content inside it, text color included. |
Installation
The Prodular UI CLI adds the source to components/ui with everything it depends on. In a project that already uses shadcn/ui, the shadcn CLI installs it from the Prodular registry too. See Installation for the first setup.
npx prodular-ui add accordion# or, with the registry in components.jsonnpx shadcn@latest add @prodular/accordion