labsUI

Accordion

Single or multiple panels with spring height animation. Closed content stays in the DOM for SEO.

npx @kznlabs/labsui add accordion

React primitives you copy into your project and own, with smooth spring motion.

Every interaction uses one spring from motion: stiffness 400, damping 30.

Yes. Native buttons, aria-expanded/controls, inert closed panels, reduced-motion aware.

Open as many panels as you like.

Each item toggles on its own.

Closed content stays in the DOM so crawlers can read it.
import {  Accordion,  AccordionContent,  AccordionItem,  AccordionTrigger,} from "@/components/ui/accordion";export function Faq() {  return (    <Accordion type="single" collapsible defaultValue="a">      <AccordionItem value="a">        <AccordionTrigger>Is it accessible?</AccordionTrigger>        <AccordionContent>          Yes, keyboard and screen reader friendly.        </AccordionContent>      </AccordionItem>    </Accordion>  );}

<Accordion>

Controlled (value + onValueChange) or uncontrolled (defaultValue).

  • children*
    ReactNode

    AccordionItems.

  • collapsible
    boolean

    single only: allow closing the open panel.

  • defaultValue
    string | string[]

    Open at first render (uncontrolled): an item, or items when type="multiple".

  • onValueChange
    ((value: string) => void) | ((value: string[]) => void)

    Called with the open item ("" when it closes), or every open item when type="multiple".

  • type
    "single" | "multiple"

    "single": one panel at a time. "multiple": independent panels.

  • value
    string | string[]

    Controlled open item ("" = none), or items when type="multiple".

PropTypeDefault
children*

AccordionItems.

ReactNode—
collapsible

single only: allow closing the open panel.

boolean—
defaultValue

Open at first render (uncontrolled): an item, or items when type="multiple".

string | string[]—
onValueChange

Called with the open item ("" when it closes), or every open item when type="multiple".

((value: string) => void) | ((value: string[]) => void)—
type

"single": one panel at a time. "multiple": independent panels.

"single" | "multiple"—
value

Controlled open item ("" = none), or items when type="multiple".

string | string[]—

<AccordionItem>

  • children*
    ReactNode

    AccordionTrigger and AccordionContent.

  • value*
    string

    Unique id within the Accordion, matched by value/defaultValue.

PropTypeDefault
children*

AccordionTrigger and AccordionContent.

ReactNode—
value*

Unique id within the Accordion, matched by value/defaultValue.

string—

<AccordionTrigger>

  • children*
    ReactNode

    Question or heading text.

  • asdefault "h3"
    "h2" | "h3" | "h4" | "h5" | "h6"

    Wrapping heading level; match the page outline (default h3).

PropTypeDefault
children*

Question or heading text.

ReactNode—
as

Wrapping heading level; match the page outline (default h3).

"h2" | "h3" | "h4" | "h5" | "h6""h3"

<AccordionContent>

Stays mounted when closed (inert, height 0) so content remains crawlable.

  • children*
    ReactNode

    Panel content; stays in the HTML while closed.

PropTypeDefault
children*

Panel content; stays in the HTML while closed.

ReactNode—

* required. Every component also takes className.