A vertically stacked set of interactive headings that reveal or hide content sections.
This is a standalone component that does not depend on the assistant-ui runtime. Use it anywhere in your application.
Installation
npx shadcn@latest add https://r.assistant-ui.com/accordion.jsonMain Component
npm install @radix-ui/react-accordion class-variance-authority"use client";import type { ComponentProps } from "react";import * as AccordionPrimitive from "@radix-ui/react-accordion";import { ChevronDownIcon } from "lucide-react";import { cva, type VariantProps } from "class-variance-authority";import { cn } from "@/lib/utils";const accordionVariants = cva( "aui-accordion group/accordion flex w-full flex-col", { variants: { variant: { default: "", outline: "rounded-lg border", ghost: "gap-2", }, }, defaultVariants: { variant: "default" }, },);function Accordion({ className, variant, ...props}: ComponentProps<typeof AccordionPrimitive.Root> & VariantProps<typeof accordionVariants>) { return ( <AccordionPrimitive.Root data-slot="accordion" data-variant={variant ?? "default"} className={cn(accordionVariants({ variant }), className)} {...props} /> );}function AccordionItem({ className, ...props}: ComponentProps<typeof AccordionPrimitive.Item>) { return ( <AccordionPrimitive.Item data-slot="accordion-item" className={cn( "aui-accordion-item group/accordion-item", "group-data-[variant=default]/accordion:border-b group-data-[variant=default]/accordion:last:border-b-0", "group-data-[variant=outline]/accordion:border-b group-data-[variant=outline]/accordion:last:border-b-0", "group-data-[variant=ghost]/accordion:rounded-lg group-data-[variant=ghost]/accordion:data-[state=open]:bg-muted/50", className, )} {...props} /> );}function AccordionTrigger({ className, children, ...props}: ComponentProps<typeof AccordionPrimitive.Trigger>) { return ( <AccordionPrimitive.Header className="flex"> <AccordionPrimitive.Trigger data-slot="accordion-trigger" className={cn( "aui-accordion-trigger group/accordion-trigger flex w-full flex-1 items-center justify-between gap-4 text-left font-medium text-sm outline-none transition-all disabled:pointer-events-none disabled:opacity-50", "group-data-[variant=default]/accordion:py-4 group-data-[variant=default]/accordion:focus-visible:ring-2 group-data-[variant=default]/accordion:focus-visible:ring-ring/50 group-data-[variant=default]/accordion:hover:underline", "group-data-[variant=outline]/accordion:px-4 group-data-[variant=outline]/accordion:py-3 group-data-[variant=outline]/accordion:focus-visible:ring-2 group-data-[variant=outline]/accordion:focus-visible:ring-ring/50 group-data-[variant=outline]/accordion:focus-visible:ring-inset group-data-[variant=outline]/accordion:hover:bg-muted/50", "group-data-[variant=ghost]/accordion:rounded-lg group-data-[variant=ghost]/accordion:px-4 group-data-[variant=ghost]/accordion:py-2 group-data-[variant=ghost]/accordion:focus-visible:ring-2 group-data-[variant=ghost]/accordion:focus-visible:ring-ring/50 group-data-[variant=ghost]/accordion:hover:bg-muted/50", className, )} {...props} > {children} <ChevronDownIcon className="pointer-events-none size-4 shrink-0 text-muted-foreground transition-transform duration-200 ease-out group-data-[state=open]/accordion-trigger:rotate-180" /> </AccordionPrimitive.Trigger> </AccordionPrimitive.Header> );}function AccordionContent({ className, children, ...props}: ComponentProps<typeof AccordionPrimitive.Content>) { return ( <AccordionPrimitive.Content data-slot="accordion-content" className="aui-accordion-content overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down" {...props} > <div className={cn( "group-data-[variant=default]/accordion:pb-4", "group-data-[variant=outline]/accordion:border-t group-data-[variant=outline]/accordion:px-4 group-data-[variant=outline]/accordion:py-3", "group-data-[variant=ghost]/accordion:px-4 group-data-[variant=ghost]/accordion:py-3", className, )} > {children} </div> </AccordionPrimitive.Content> );}export { Accordion, AccordionItem, AccordionTrigger, AccordionContent, accordionVariants,};Usage
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from "@/components/assistant-ui/accordion";
export function Example() {
return (
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger>Section 1</AccordionTrigger>
<AccordionContent>Content for section 1.</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>Section 2</AccordionTrigger>
<AccordionContent>Content for section 2.</AccordionContent>
</AccordionItem>
</Accordion>
);
}Examples
Variants
Use the variant prop on Accordion to change the visual style. Child components inherit the variant automatically.
// Default - border-bottom separator
<Accordion type="single" collapsible variant="default">
<AccordionItem value="item-1">
<AccordionTrigger>...</AccordionTrigger>
<AccordionContent>...</AccordionContent>
</AccordionItem>
</Accordion>
// Outline - bordered container
<Accordion type="single" collapsible variant="outline">
<AccordionItem value="item-1">
<AccordionTrigger>...</AccordionTrigger>
<AccordionContent>...</AccordionContent>
</AccordionItem>
</Accordion>
// Ghost - separated cards
<Accordion type="single" collapsible variant="ghost">
<AccordionItem value="item-1">
<AccordionTrigger>...</AccordionTrigger>
<AccordionContent>...</AccordionContent>
</AccordionItem>
</Accordion>Multiple Items Open
Use type="multiple" to allow multiple items to be open simultaneously.
<Accordion type="multiple">
<AccordionItem value="item-1">
<AccordionTrigger>First Section</AccordionTrigger>
<AccordionContent>Content 1</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>Second Section</AccordionTrigger>
<AccordionContent>Content 2</AccordionContent>
</AccordionItem>
</Accordion>With Icons
Add icons or custom elements inside the trigger.
Controlled
Use value and onValueChange for controlled accordion state.
Current value: item-1
FAQ Section
A practical example of using accordion for a FAQ section.
Frequently Asked Questions
API Reference
Composable API
| Component | Description |
|---|---|
Accordion | The root component that manages accordion state and variant. |
AccordionItem | A single collapsible section container. |
AccordionTrigger | The clickable header that toggles content visibility. |
AccordionContent | The collapsible content panel. |
Accordion
The root component that manages accordion state. Set variant here to style all child components.
AccordionPropstyperequired: "single" | "multiple"Whether only one or multiple items can be open at once.
collapsible: boolean= falseWhen type is 'single', allows closing the open item by clicking it again.
defaultValue?: string | string[]The default open item(s) (uncontrolled).
value?: string | string[]The controlled open item(s).
onValueChange?: (value: string | string[]) => voidCallback when the open item(s) change.
variant: "default" | "outline" | "ghost"= "default"The visual style of the accordion. Child components inherit this automatically.
className?: stringAdditional CSS classes.
AccordionItem
A single collapsible section container.
AccordionItemPropsvaluerequired: stringA unique identifier for this item.
disabled?: booleanWhether the item is disabled.
className?: stringAdditional CSS classes.
AccordionTrigger
The clickable header that toggles content visibility.
AccordionTriggerPropsclassName?: stringAdditional CSS classes.
AccordionContent
The collapsible content panel.
AccordionContentPropsclassName?: stringAdditional CSS classes.
Style Variants (CVA)
| Export | Description |
|---|---|
accordionVariants | Styles for the accordion container. |
import { accordionVariants } from "@/components/assistant-ui/accordion";
<div className={accordionVariants({ variant: "outline" })}>
Custom Accordion Container
</div>