import { ChevronsUpDownIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
const row = "rounded-md border-[0.5px] border-border-muted px-3 py-2 font-mono text-sm";
export default function CollapsibleBasic() {
return (
<Collapsible className="flex w-full max-w-sm flex-col gap-2">
<div className="flex items-center justify-between gap-4">
<span className="text-sm font-medium">Ada Park starred 3 projects</span>
<CollapsibleTrigger
render={<Button variant="ghost" size="icon-sm" aria-label="Toggle starred projects" />}
>
<ChevronsUpDownIcon />
</CollapsibleTrigger>
</div>
<div className={row}>website-redesign</div>
<CollapsibleContent className="flex flex-col gap-2">
<div className={row}>mobile-app</div>
<div className={row}>brand-guidelines</div>
</CollapsibleContent>
</Collapsible>
);
}- Add the registryOnce per project
pnpm dlx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json - Add collapsible
pnpm dlx shadcn@latest add @jarvis/collapsible
Usage
import { Button } from "@/components/ui/button";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
export function Details() {
return (
<Collapsible>
<CollapsibleTrigger render={<Button variant="ghost" size="sm" />}>
Show details
</CollapsibleTrigger>
<CollapsibleContent>
<p className="text-sm text-muted-foreground">Created by Ada Park on March 4.</p>
</CollapsibleContent>
</Collapsible>
);
}CollapsibleTrigger is an unstyled button. Pass render to draw it as a Button.
Composition
Examples
Open by default
defaultOpen starts it open. The trigger gets data-panel-open while open, which you can use to
rotate an icon.
import { ChevronRightIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
export default function CollapsibleOpenByDefault() {
return (
<Collapsible defaultOpen className="flex w-full max-w-sm flex-col gap-2">
<CollapsibleTrigger
render={
<Button
variant="ghost"
size="sm"
className="-ml-2 self-start [&_svg]:transition-transform [&[data-panel-open]_svg]:rotate-90"
/>
}
>
<ChevronRightIcon />
Advanced options
</CollapsibleTrigger>
<CollapsibleContent>
<FieldGroup className="gap-3 pb-1">
<Field>
<FieldLabel htmlFor="production-branch">Production branch</FieldLabel>
<Input id="production-branch" defaultValue="main" />
</Field>
<Field>
<FieldLabel htmlFor="root-directory">Root directory</FieldLabel>
<Input id="root-directory" defaultValue="apps/web" />
</Field>
</FieldGroup>
</CollapsibleContent>
</Collapsible>
);
}Props
The tables leave out className, style and render. Parts built on Base UI take them as its styling and composition guides describe.
Collapsible
| Prop | Type | Default |
|---|---|---|
openWhether the collapsible panel is currently open. To render an uncontrolled collapsible, use the | boolean | — |
defaultOpenWhether the collapsible panel is initially open. To render a controlled collapsible, use the | boolean | false |
onOpenChangeEvent handler called when the panel is opened or closed. | ((open: boolean, eventDetails: CollapsibleRootChangeEventDetails) => void) | — |
disabledWhether the component should ignore user interaction. | boolean | false |
CollapsibleTrigger
| Prop | Type | Default |
|---|---|---|
nativeButtonWhether the component renders a native | boolean | true |
CollapsibleContent
| Prop | Type | Default |
|---|---|---|
hiddenUntilFoundAllows the browser's built-in page search to find and expand the panel contents. Overrides the | boolean | false |
keepMountedWhether to keep the element in the DOM while the panel is hidden.
This prop is ignored when | boolean | false |