Skip to content
SevenUI
Esc
navigateopen⌘Jpreview
Sign in
On this page

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&apos;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.json

Usage

"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 booleanhidden="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.

Was this page helpful?