Skip to content
WANCRAFT

B.38Cards & Containers

Fluid Accordion

An accessible accordion whose panels glide open to their natural height, with single or multiple open items.

NewReactCSSTailwindbasic

Overview

Fluid Accordion animates each panel by transitioning grid-template-rows from 0fr to 1fr, so content of any height opens smoothly without measuring the DOM or running JavaScript per frame. It supports single or multiple open items, controlled and uncontrolled state, a collapsible switch for single mode, and a chevron or plus-to-minus indicator. Triggers are real buttons inside headings with aria-expanded and aria-controls, panels are labelled regions, collapsed content is made inert, and Arrow keys, Home and End move between headers.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/fluid-accordion.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/fluid-accordion.json

Method 02 · Copy and paste

  1. 1. No extra dependencies — React and Tailwind CSS only.
  2. 2. Copy the source from the Code tab into components/ui/fluid-accordion.tsx.
  3. 3. Import it and adjust props.
Dependencies
None
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { FluidAccordion, type FluidAccordionItem } from "@/components/ui/fluid-accordion";

export function FluidAccordionExample() {
  const items: FluidAccordionItem[] = [
    { id: "shipping", title: "How long does shipping take?", content: <p>Orders leave the studio within two working days.</p> },
    { id: "returns", title: "Can I return an item?", content: <p>Yes, within 30 days in original condition.</p> },
    { id: "care", title: "How do I care for it?", content: <p>Wipe with a dry cloth; avoid direct sunlight.</p> },
  ];

  return (
    <FluidAccordion items={items} defaultValue={["shipping"]} />
  );
}

03Props

PropTypeDefaultDescription
itemsFluidAccordionItem[]—{ id: string; title: ReactNode; content: ReactNode; disabled?: boolean }.
type"single" | "multiple""single"At most one open item, or any number.
valuestring[]—Open item ids (controlled).
defaultValuestring[]—Initially open item ids (uncontrolled).
onValueChange(value: string[]) => void—Called with the next list of open ids.
collapsiblebooleantrueSingle mode: allow closing the open item so none is open.
icon"chevron" | "plus""chevron"Rotating chevron, or a plus that morphs into a minus.
variant"lined" | "cards""lined"Hairline separators, or a surface per item.
showIndexbooleantrueShow a mono index before each title.
durationnumber320Open / close duration in ms.
headingLevel2 | 3 | 4 | 5 | 63Heading level wrapping each trigger.
accentstring"#FF7448"Open index, indicator and focus ring colour.
...propsHTMLAttributes<HTMLDivElement>—Native attributes are forwarded to the wrapper.

04Features

  • 01Height animation with grid-template-rows 0fr → 1fr: no measuring, no per-frame JavaScript
  • 02Single or multiple open items, controlled (value) or uncontrolled (defaultValue)
  • 03Collapsible switch for single mode
  • 04Chevron or plus-to-minus indicator morph
  • 05Lined and card variants, optional mono index numbers, configurable heading level
motion · tweeninput · clickinput · keyboardinput · focus

05Accessibility

  • Each trigger is a <button> inside a heading with aria-expanded and aria-controls.
  • Panels use role="region" with aria-labelledby pointing at their trigger.
  • Collapsed panels are inert, so their content is neither focusable nor read by screen readers.
  • Arrow Up / Down move between headers and wrap; Home and End jump to the first and last.
  • An open item that cannot be collapsed is marked aria-disabled.
  • With prefers-reduced-motion the panels open and close instantly.