Skip to content
    Style: Wireframe

    Components · Layout

    Accordion

    Sections on native details, one open at a time if you like. Keyboard and find-in-page, no JavaScript.

    29% of the 2,073 sites in The UI Index have a accordion (596 sites).

    Used in UI Pro: FAQ

    Connect a repository

    Pick a GitHub repository; every push to main deploys.

    Add a domain

    Point a CNAME at your project and the certificate follows within minutes.

    Invite your team

    Teammates get edit rights on every project in the workspace.

    Both previews render the same markup; the HTML tab below is that markup without a framework.

    Install

    React
    npx shadcn@latest add https://www.themes.dev/ui/r/accordion.json
    Astro
    npx shadcn@latest add https://www.themes.dev/ui/r/astro/accordion.json

    Or copy the files below into your project. They need clsx, tailwind-merge, and the themes.dev UI theme. The HTML needs only the compiled CSS.

    accordion.tsx
    import { cn } from '@/lib/utils';
    import { accordion, CHEVRON_PATH, type AccordionItem } from './accordion.variants';
    
    export type { AccordionItem };
    
    export interface AccordionProps {
      items: AccordionItem[];
      /** One open at a time: the items share this name (native exclusive details). */
      single?: string;
      className?: string;
    }
    
    /** Sections on native <details>; the browser handles keyboard, find-in-page and the exclusive group. */
    export function Accordion({ items, single, className }: AccordionProps) {
      return (
        <div className={cn(accordion.root, className)}>
          {items.map((it, k) => (
            <details key={k} name={single} open={it.open} className={accordion.item}>
              <summary className={accordion.summary}>
                {it.title}
                <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className={accordion.chevron}><path d={CHEVRON_PATH} /></svg>
              </summary>
              <p className={accordion.content}>{it.content}</p>
            </details>
          ))}
        </div>
      );
    }
    accordion.variants.ts
    /** Sections that open and close, on native <details>: keyboard, find-in-page and no JavaScript. With `single`, the
     *  items share a name, so opening one closes the others (the browser does it). Items sit on their own grounds,
     *  separated by space, not by rules; the chevron turns, and stands still under reduced motion. */
    export const accordion = {
      root: 'grid w-full gap-2',
      item: 'group rounded-lg bg-muted/60 transition-colors open:bg-muted',
      summary:
        'flex min-h-12 cursor-pointer list-none items-center justify-between gap-4 rounded-lg px-4 py-3 text-sm font-medium text-pretty transition-colors hover:bg-accent active:bg-pressed group-open:rounded-b-none [&::-webkit-details-marker]:hidden',
      chevron: 'size-4 shrink-0 text-muted-foreground transition-transform duration-200 group-open:rotate-180',
      content: 'px-4 pt-1 pb-4 text-sm text-pretty text-muted-foreground',
    };
    
    export type AccordionItem = { title: string; content: string; open?: boolean };
    export const CHEVRON_PATH = 'M4 6l4 4 4-4';