Accordion
A vertically stacked set of interactive headings that each reveal an associated panel of content, built on the Base UI Accordion primitive.
"use client";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/registry/base/ui/accordion";
export default function AccordionDemo() {
return (
<Accordion className="w-full max-w-md" defaultValue={["item-1"]}>
<AccordionItem value="item-1">
<AccordionTrigger>Product Information</AccordionTrigger>
<AccordionContent>
<p className="mb-2 last:mb-0">
Our flagship product combines cutting-edge technology with sleek
design. Built from premium materials, it offers reliability and
performance for everyday use.
</p>
<p className="mb-2 last:mb-0">
Every unit is rigorously tested before shipping to ensure it
meets our high quality standards.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>Shipping Details</AccordionTrigger>
<AccordionContent>
<p className="mb-2 last:mb-0">
We offer worldwide shipping through trusted courier partners.
Standard delivery takes 3-5 business days, while express
shipping ensures next-day delivery.
</p>
<p className="mb-2 last:mb-0">
All orders are carefully packaged and fully insured. Track your
shipment in real time from our dashboard.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-3">
<AccordionTrigger>Return Policy</AccordionTrigger>
<AccordionContent>
<p className="mb-2 last:mb-0">
We stand behind our products with a comprehensive 30-day return
policy. If you're not completely satisfied, simply return
the item in its original condition.
</p>
<p className="mb-2 last:mb-0">
Our hassle-free return process includes free return shipping and
full refunds processed within 48 hours of receiving the return.
</p>
</AccordionContent>
</AccordionItem>
</Accordion>
);
}
Installation
npx shadcn@latest add https://sevenui.dev/r/accordion.jsonUsage
"use client";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
export default function AccordionDemo() {
return (
<Accordion className="w-full max-w-md" defaultValue={["item-1"]}>
<AccordionItem value="item-1">
<AccordionTrigger>Is it accessible?</AccordionTrigger>
<AccordionContent>
Yes. It adheres to the WAI-ARIA design pattern.
</AccordionContent>
</AccordionItem>
</Accordion>
);
}
Examples
Multiple open panels
"use client";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/registry/base/ui/accordion";
const faqs = [
{
value: "shipping",
question: "How long does shipping take?",
answer: "Orders ship within 24 hours and arrive in 3-5 business days.",
},
{
value: "returns",
question: "What is the return policy?",
answer: "Returns are free within 30 days of delivery.",
},
{
value: "warranty",
question: "Is there a warranty?",
answer: "Every product includes a two-year limited warranty.",
},
];
export default function AccordionMultiple() {
return (
<Accordion
multiple
defaultValue={["shipping", "returns"]}
className="w-full max-w-md"
>
{faqs.map((faq) => (
<AccordionItem key={faq.value} value={faq.value}>
<AccordionTrigger>{faq.question}</AccordionTrigger>
<AccordionContent>{faq.answer}</AccordionContent>
</AccordionItem>
))}
</Accordion>
);
}
In a card
"use client";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/registry/base/ui/accordion";
const items = [
{
value: "included",
question: "What's included in the Pro plan?",
answer: "Unlimited projects, priority support, and team analytics.",
},
{
value: "billing",
question: "Can I switch billing periods?",
answer: "Yes — changes take effect at the start of the next cycle.",
},
{
value: "cancel",
question: "How do I cancel?",
answer: "From settings, anytime. Your data stays for 30 days.",
},
];
export default function AccordionCard() {
return (
<Accordion
defaultValue={["included"]}
className="w-full max-w-md rounded-xl bg-card px-4 ring-1 ring-foreground/10"
>
{items.map((item) => (
<AccordionItem
key={item.value}
value={item.value}
className="last:border-b-0"
>
<AccordionTrigger>{item.question}</AccordionTrigger>
<AccordionContent>{item.answer}</AccordionContent>
</AccordionItem>
))}
</Accordion>
);
}
Split items
"use client";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/registry/base/ui/accordion";
const items = [
{
value: "design",
question: "Do you offer design files?",
answer: "Figma files ship with every release.",
},
{
value: "themes",
question: "Can I use my own theme?",
answer: "All components read your CSS variables — swap the palette freely.",
},
{
value: "support",
question: "Where do I get help?",
answer: "GitHub discussions and the community Discord.",
},
];
export default function AccordionSplit() {
return (
<Accordion defaultValue={["design"]} className="w-full max-w-md space-y-2">
{items.map((item) => (
<AccordionItem
key={item.value}
value={item.value}
className="rounded-lg border bg-muted/30 px-4 last:border-b"
>
<AccordionTrigger>{item.question}</AccordionTrigger>
<AccordionContent>{item.answer}</AccordionContent>
</AccordionItem>
))}
</Accordion>
);
}
API reference
Accordion
Extends the
Base UI Accordion
Root — all its props apply. value/defaultValue are arrays of the
open item values (defaultValue={["item-1"]}), not a single value.
| Prop | Type | Default |
|---|---|---|
value / defaultValue |
string[] |
— |
onValueChange |
(value: string[]) => void |
— |
multiple |
boolean (renamed from openMultiple in 1.7) |
false |
hiddenUntilFound |
boolean — hidden="until-found" panels reveal via find-in-page |
false |
disabled |
boolean |
false |
AccordionItem
Takes the item value (and disabled).
AccordionTrigger
A native <button> inside an <h3> heading (Accordion.Header) —
override the heading level via render on the primitive’s Header when
composing directly. The open state styles via data-panel-open
(presence) — not data-open, which lives on Item/Panel/Root. A disabled
trigger stays focusable with aria-disabled="true" — style it with
data-disabled:, not disabled:.
AccordionContent
Open/close animates via the animate-accordion-down /
animate-accordion-up utilities. Their keyframes ship in this
component’s registry item (the CLI merges them into your CSS); when
copying the source manually, add them yourself:
@theme inline {
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-accordion-up: accordion-up 0.2s ease-out;
}
@keyframes accordion-down {
from { height: 0; }
to { height: var(--accordion-panel-height); }
}
@keyframes accordion-up {
from { height: var(--accordion-panel-height); }
to { height: 0; }
}
--accordion-panel-height is set by Base UI on the panel.