Collapsible
A panel that expands and collapses, with a height animation.
3 files changed
src/app/page.tsx
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '@/components/ui/collapsible'
import { Button } from '@/components/ui/button'
export default function CollapsibleDemo() {
return (
<Collapsible className="w-full max-w-sm space-y-2">
<div className="flex items-center justify-between gap-4">
<h4 className="text-sm font-semibold">3 files changed</h4>
<CollapsibleTrigger
render={
<Button variant="ghost" size="sm" className="group" aria-label="Toggle file list">
<ChevronsIcon className="transition-transform group-data-[panel-open]:rotate-180" />
</Button>
}
/>
</div>
<div className="rounded-md border border-border px-4 py-2 font-mono text-sm">src/app/page.tsx</div>
<CollapsibleContent>
<div className="space-y-2">
<div className="rounded-md border border-border px-4 py-2 font-mono text-sm">src/components/header.tsx</div>
<div className="rounded-md border border-border px-4 py-2 font-mono text-sm">src/lib/utils.ts</div>
</div>
</CollapsibleContent>
</Collapsible>
)
}
function ChevronsIcon({ className }: { className?: string }) {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" className={className} aria-hidden="true">
<path d="m7 15 5 5 5-5M7 9l5-5 5 5" />
</svg>
)
}
Built on Base UI
Installation
pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/collapsible.jsonNeeds a React + Tailwind project set up with shadcn. Copies the component source straight into your project, so you can edit it.
Collapsible imports cn() from lib/utils.ts — add it too if you don't have it yet:
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Usage
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '@/components/ui/collapsible'
import { Button } from '@/components/ui/button'
<Collapsible>
<CollapsibleTrigger render={<Button variant="outline">Toggle</Button>} />
<CollapsibleContent>Hidden until the trigger is pressed.</CollapsibleContent>
</Collapsible>Examples
Controlled
'use client'
import * as React from 'react'
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '@/components/ui/collapsible'
import { Button } from '@/components/ui/button'
export default function CollapsibleControlled() {
const [open, setOpen] = React.useState(false)
return (
<Collapsible open={open} onOpenChange={setOpen} className="w-full max-w-sm">
<CollapsibleTrigger render={<Button variant="outline">{open ? 'Hide details' : 'Show details'}</Button>} />
<CollapsibleContent>
<p className="pt-3 text-sm text-muted-foreground">
Details are kept out of the way until they're asked for. The panel animates to its natural height, and its
content stays out of the tab order while it's closed.
</p>
</CollapsibleContent>
</Collapsible>
)
}
API Reference
| Name | Type | Default | Description |
|---|---|---|---|
| open / onOpenChange | boolean / (open: boolean) => void | — | Control the open state from outside (set on Collapsible). |
| defaultOpen | boolean | false | Initial open state (uncontrolled). |
| disabled | boolean | false | Ignores user interaction. |
| CollapsibleTrigger render | ReactElement | — | Renders the trigger as a different element, e.g. a Button. It gets data-panel-open while open. |
| CollapsibleContent keepMounted | boolean | false | Keeps the content in the DOM while closed. |
| CollapsibleContent hiddenUntilFound | boolean | false | Lets the browser's find-in-page open the panel when it matches. |