Files
2026-05-27 23:47:53 +01:00

6.2 KiB

Collapsible

(no submodules)

- collapsible.variants — `collapsibleVariants`, `coll…
  • collapsible.variants — collapsibleVariants, collapsibleTriggerVariants, and collapsibleContentVariants are the cva (class-variance-autho…

  • collapsible.variants — collapsibleVariants, `coll…

  • collapsible.variants — collapsibleVariants, collapsibleTriggerVariants, and collapsibleContentVariants are the cva (class-variance-autho…

  • collapsible.variants — collapsibleVariants, `coll…

  • collapsible.variants — collapsibleVariants, collapsibleTriggerVariants, and collapsibleContentVariants are the cva (class-variance-autho…

  • collapsible.variants — collapsibleVariants, `coll…

  • collapsible.variants — collapsibleVariants, collapsibleTriggerVariants, and collapsibleContentVariants are the cva (class-variance-autho…

  • collapsible.variants — collapsibleVariants, collapsibleTriggerVariants, and collapsibleContentVariants are the cva (class-variance-autho…

Purpose

<Collapsible>, <CollapsibleTrigger>, and <CollapsibleContent> are the chassis single-section disclosure primitives built on @radix-ui/react-collapsible. Radix supplies the WAI-ARIA disclosure semantics: the trigger renders a <button> with aria-expanded reflecting the open state and aria-controls referencing the content panel; the content carries role="region" (when given an accessible name) and unmounts while closed. The chassis layers a small cva recipe for structural alignment plus a data-[state=open]:rotate-180 hook so a sibling chevron icon flips when the panel opens.

Use this primitive for ONE open/closed pair (e.g. an "advanced settings" disclosure or an FAQ item that does not belong to a sibling-managed group). For sibling panels with mutual-exclusion (type="single") or multi-open (type="multiple") semantics, use <Accordion> instead.

Features

  • WAI-ARIA disclosure semantics auto-managed by Radix (trigger aria-expanded / aria-controls, content role="region" when titled).
  • Keyboard activation: Space and Enter both toggle the trigger.
  • Controlled (open / onOpenChange) and uncontrolled (defaultOpen) modes.
  • disabled prop short-circuits the toggle while keeping the trigger focusable for parity with <button disabled>.
  • Smooth open/close animation via --radix-collapsible-content-height (animate-collapsible-down/up keyframes); collapses to none under prefers-reduced-motion: reduce.
  • Theme-driven cva overrides for Collapsible, CollapsibleTrigger, and CollapsibleContent.
  • All sub-components forward refs to their underlying Radix elements.
  • Trigger cva carries focus-visible ring + hover-bg recipes so the disclosure looks like the chassis Button family without being one.

Usage: Basic Example

import {
    Collapsible,
    CollapsibleContent,
    CollapsibleTrigger,
} from "@suaveplan/react-ui";

export function AdvancedOptions() {
    return (
        <Collapsible>
            <CollapsibleTrigger>Advanced options</CollapsibleTrigger>
            <CollapsibleContent>
                <p>Hidden content revealed when toggled.</p>
            </CollapsibleContent>
        </Collapsible>
    );
}

Usage: Advanced Example

import {
    Button,
    Collapsible,
    CollapsibleContent,
    CollapsibleTrigger,
} from "@suaveplan/react-ui";
import { ChevronDownIcon } from "lucide-react";
import { useState } from "react";

export function FilterPanel({ children }: { children: React.ReactNode }) {
    const [open, setOpen] = useState(false);
    return (
        <Collapsible open={open} onOpenChange={setOpen}>
            <CollapsibleTrigger asChild>
                <Button variant="outline" className="w-full justify-between">
                    {open ? "Hide filters" : "Show filters"}
                    <ChevronDownIcon
                        data-icon="chevron"
                        className="size-4 transition-transform data-[state=open]:rotate-180"
                        aria-hidden
                    />
                </Button>
            </CollapsibleTrigger>
            <CollapsibleContent className="mt-3 rounded-md border p-3">
                {children}
            </CollapsibleContent>
        </Collapsible>
    );
}

API Reference

<Collapsible>

Renders the Radix Root that owns the open/closed state machine.

Prop Type Default Description
open boolean uncontrolled Controlled open state.
defaultOpen boolean false Initial open state for uncontrolled use.
onOpenChange (open: boolean) => void none Fires on every open / close transition.
disabled boolean false When true, the trigger no longer toggles state.

<CollapsibleTrigger>

Wraps the Radix Trigger; renders a <button> (or polymorphically the child via asChild).

Prop Type Default Description
asChild boolean false Merge the chassis trigger props onto the rendered child instead of wrapping in a <button>. Useful for binding to a <Button>.

<CollapsibleContent>

Wraps the Radix Content. Children unmount while closed (Radix default).

Implementation Notes

  • The chassis NEVER assigns a numeric z-index (per the shadcn skill rule); the disclosure stays in flow and stacking is implicit.
  • The animation classes (animate-collapsible-down/up) require the chassis Tailwind preset to register the corresponding keyframes (shipped in @suaveplan/react-ui/styles/global.css).
  • Radix unmounts content when closed by default; render a wrapper around the trigger if you need persistent layout (e.g. a <section> element that always appears in the DOM).
  • The trigger cva matches the chassis <Button variant="ghost"> recipe so a disclosure used alone looks like a Button without being one. Use asChild to literally render a <Button> when consistency with the surrounding button cluster matters.
  • disabled flows through to the underlying <button> so screen-readers announce the disabled state correctly via the native attribute.