Free shadcn/ui collapsible for React — built on Radix. An accessible show/hide disclosure: a controlled toggle, a chevron trigger, show-more text, a sidebar filter group, nested trees, and expandable rows.

Installation

1 Configure registry — once per project
{
  "registries": {
    "@designrevision": "https://registry.designrevision.com/r/{name}.json"
  }
}

Add to your existing components.json. Requires shadcn/ui v2.3+.

2 Install the component

Packages

@radix-ui/react-collapsible
utils

Props

No props documented yet.

Copied!
components/ui/collapsible.tsx
"use client"

import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"

function Collapsible({
  ...props
}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
  return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />
}

function CollapsibleTrigger({
  ...props
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
  return (
    <CollapsiblePrimitive.CollapsibleTrigger
      data-slot="collapsible-trigger"
      {...props}
    />
  )
}

function CollapsibleContent({
  ...props
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
  return (
    <CollapsiblePrimitive.CollapsibleContent
      data-slot="collapsible-content"
      {...props}
    />
  )
}

export { Collapsible, CollapsibleTrigger, CollapsibleContent }

Examples

Basic

The canonical collapsible — a toggle that reveals extra items, controlled with open state.

Packages

lucide-react
collapsible
button

Props

No props documented yet.

Copied!
components/ui/collapsible-demo-01.tsx
"use client"

import * as React from "react"
import { ChevronsUpDown } from "lucide-react"

import { Button } from "@/components/ui/button"
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible"

export default function CollapsibleDemo01() {
  const [open, setOpen] = React.useState(false)

  return (
    <Collapsible
      open={open}
      onOpenChange={setOpen}
      className="flex w-full max-w-sm flex-col gap-2"
    >
      <div className="flex items-center justify-between gap-4 px-1">
        <h4 className="text-sm font-semibold">
          @peduarte starred 3 repositories
        </h4>
        <CollapsibleTrigger asChild>
          <Button variant="ghost" size="icon" className="size-8">
            <ChevronsUpDown />
            <span className="sr-only">Toggle</span>
          </Button>
        </CollapsibleTrigger>
      </div>
      <div className="rounded-md border px-4 py-2 font-mono text-sm">
        @radix-ui/primitives
      </div>
      <CollapsibleContent className="flex flex-col gap-2">
        <div className="rounded-md border px-4 py-2 font-mono text-sm">
          @radix-ui/colors
        </div>
        <div className="rounded-md border px-4 py-2 font-mono text-sm">
          @stitches/react
        </div>
      </CollapsibleContent>
    </Collapsible>
  )
}

Chevron trigger

A full-width trigger with a chevron that rotates on open, via `group-data-[state=open]`.

Packages

lucide-react
collapsible

Props

No props documented yet.

Copied!
components/ui/collapsible-chevron-01.tsx
import { ChevronRight } from "lucide-react"

import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible"

export default function CollapsibleChevron01() {
  return (
    <Collapsible className="w-full max-w-sm rounded-md border">
      <CollapsibleTrigger className="group flex w-full items-center justify-between p-4 text-sm font-medium">
        What is your refund policy?
        <ChevronRight className="size-4 transition-transform group-data-[state=open]:rotate-90" />
      </CollapsibleTrigger>
      <CollapsibleContent className="text-muted-foreground px-4 pb-4 text-sm">
        We offer a 30-day money-back guarantee on all plans — no questions
        asked. Refunds are processed to your original payment method.
      </CollapsibleContent>
    </Collapsible>
  )
}

Show more / less

A read-more pattern — the trigger label flips between Show more and Show less.

Packages

collapsible
button

Props

No props documented yet.

Copied!
components/ui/collapsible-text-01.tsx
"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible"

export default function CollapsibleText01() {
  const [open, setOpen] = React.useState(false)

  return (
    <Collapsible open={open} onOpenChange={setOpen} className="w-full max-w-md">
      <p className="text-sm leading-relaxed">
        Embla is a bare-bones carousel library with great fluid motion and
        awesome swipe precision. It is library agnostic, dependency free, and
        100% open source.
      </p>
      <CollapsibleContent>
        <p className="mt-2 text-sm leading-relaxed">
          It ships a tiny core with optional plugins for autoplay, auto-scroll,
          class names, and more. The shadcn Carousel wraps it with styling and
          accessible controls.
        </p>
      </CollapsibleContent>
      <CollapsibleTrigger asChild>
        <Button variant="link" className="mt-1 h-auto p-0">
          {open ? "Show less" : "Show more"}
        </Button>
      </CollapsibleTrigger>
    </Collapsible>
  )
}

Filter group

A collapsible sidebar filter — a category group of checkboxes that folds away.

Packages

lucide-react
collapsible
checkbox
label

Props

No props documented yet.

Copied!
components/ui/collapsible-filter-01.tsx
import { ChevronDown } from "lucide-react"

import { Checkbox } from "@/components/ui/checkbox"
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible"
import { Label } from "@/components/ui/label"

const categories = ["Electronics", "Clothing", "Home & Garden", "Sports"]

export default function CollapsibleFilter01() {
  return (
    <div className="w-full max-w-xs">
      <Collapsible defaultOpen className="rounded-md border p-3">
        <CollapsibleTrigger className="group flex w-full items-center justify-between text-sm font-medium">
          Category
          <ChevronDown className="size-4 transition-transform group-data-[state=open]:rotate-180" />
        </CollapsibleTrigger>
        <CollapsibleContent className="mt-3 space-y-2.5">
          {categories.map((category) => (
            <div key={category} className="flex items-center gap-2">
              <Checkbox id={category} />
              <Label htmlFor={category} className="text-sm font-normal">
                {category}
              </Label>
            </div>
          ))}
        </CollapsibleContent>
      </Collapsible>
    </div>
  )
}

Nested (file tree)

Collapsibles inside collapsibles — a folder/file tree with rotating chevrons.

Packages

lucide-react
collapsible

Props

No props documented yet.

Copied!
components/ui/collapsible-nested-01.tsx
import { ChevronRight, FileText, Folder } from "lucide-react"

import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible"

export default function CollapsibleNested01() {
  return (
    <div className="w-full max-w-xs text-sm">
      <Collapsible defaultOpen>
        <CollapsibleTrigger className="group hover:bg-accent flex w-full items-center gap-1.5 rounded-md px-2 py-1.5">
          <ChevronRight className="size-4 transition-transform group-data-[state=open]:rotate-90" />
          <Folder className="size-4" />
          src
        </CollapsibleTrigger>
        <CollapsibleContent className="ml-4 border-l pl-2">
          <Collapsible>
            <CollapsibleTrigger className="group hover:bg-accent flex w-full items-center gap-1.5 rounded-md px-2 py-1.5">
              <ChevronRight className="size-4 transition-transform group-data-[state=open]:rotate-90" />
              <Folder className="size-4" />
              components
            </CollapsibleTrigger>
            <CollapsibleContent className="ml-4 border-l pl-2">
              <div className="flex items-center gap-1.5 px-2 py-1.5">
                <FileText className="size-4" />
                button.tsx
              </div>
              <div className="flex items-center gap-1.5 px-2 py-1.5">
                <FileText className="size-4" />
                card.tsx
              </div>
            </CollapsibleContent>
          </Collapsible>
          <div className="flex items-center gap-1.5 px-2 py-1.5">
            <FileText className="size-4" />
            index.ts
          </div>
        </CollapsibleContent>
      </Collapsible>
    </div>
  )
}

Expandable row

A list row that expands to reveal details — the order/record disclosure pattern.

Packages

lucide-react
collapsible
badge

Props

No props documented yet.

Copied!
components/ui/collapsible-details-01.tsx
import { ChevronDown } from "lucide-react"

import { Badge } from "@/components/ui/badge"
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible"

export default function CollapsibleDetails01() {
  return (
    <Collapsible className="w-full max-w-md rounded-lg border">
      <CollapsibleTrigger className="group flex w-full items-center justify-between p-4">
        <div className="flex items-center gap-3">
          <span className="font-medium">Order #3201</span>
          <Badge variant="secondary">Shipped</Badge>
        </div>
        <ChevronDown className="size-4 transition-transform group-data-[state=open]:rotate-180" />
      </CollapsibleTrigger>
      <CollapsibleContent className="space-y-1.5 border-t px-4 py-3 text-sm">
        <div className="flex justify-between">
          <span className="text-muted-foreground">Items</span>
          <span>3</span>
        </div>
        <div className="flex justify-between">
          <span className="text-muted-foreground">Total</span>
          <span>$148.00</span>
        </div>
        <div className="flex justify-between">
          <span className="text-muted-foreground">Tracking</span>
          <span>1Z999AA10123456784</span>
        </div>
      </CollapsibleContent>
    </Collapsible>
  )
}

Frequently asked questions

It is an accessible show/hide disclosure built on @radix-ui/react-collapsible — three parts: Collapsible (the root), CollapsibleTrigger (the button that toggles it), and CollapsibleContent (the region that shows or hides). Radix handles the open state, focus, and ARIA wiring.
Use a Collapsible to toggle a single region open or closed. Use an Accordion for a set of items where opening one can close the others. Accordion is built for grouped sections (like an FAQ); Collapsible is one independent show/hide.
Pass open and onOpenChange for a controlled collapsible: const [open, setOpen] = React.useState(false), then . That lets you flip a trigger label (Show more / Show less) or sync the state elsewhere. For uncontrolled use, pass defaultOpen instead.
Add the group class to the CollapsibleTrigger and a rotation on the icon keyed to the open state: . The trigger gets data-state="open" / "closed", so the icon turns when the section expands.
Radix exposes the content height as --radix-collapsible-content-height. Add a collapsible-down / collapsible-up keyframe that animates from 0 to that variable (and back), and apply it on data-[state=open] / data-[state=closed]. Without it the section toggles instantly, which is fine for most cases.
Yes — put a Collapsible inside another Collapsible's content for tree-like structures (a file explorer, nested filters). Each manages its own state independently. The Nested example shows a folder/file tree.