Collapsible
An interactive component which expands/collapses a panel.
Kobalte
The Collapsible component is built on top of Kobalte Collapsible, which provides the accessible disclosure primitive and keyboard behavior.
Order #4189
StatusShipped
import { ChevronsUpDown } from "lucide-solid";import { createSignal } from "solid-js";import { Button } from "~/components/ui/button";import { Collapsible, CollapsibleContent, CollapsibleTrigger,} from "~/components/ui/collapsible";
export default function CollapsibleDemo() { const [open, setOpen] = createSignal(false);
return ( <Collapsible open={open()} onOpenChange={setOpen} class="flex w-[350px] flex-col gap-2"> <div class="flex items-center justify-between gap-4 px-4"> <h4 class="text-sm font-semibold">Order #4189</h4> <CollapsibleTrigger as={Button} variant="ghost" size="icon" class="size-8" aria-label="Toggle details" > <ChevronsUpDown /> </CollapsibleTrigger> </div> <div class="flex items-center justify-between rounded-md border px-4 py-2 text-sm"> <span class="text-muted-foreground">Status</span> <span class="font-medium">Shipped</span> </div> <CollapsibleContent class="flex flex-col gap-2"> <div class="rounded-md border px-4 py-2 text-sm"> <p class="font-medium">Shipping address</p> <p class="text-muted-foreground">100 Market St, San Francisco</p> </div> <div class="rounded-md border px-4 py-2 text-sm"> <p class="font-medium">Items</p> <p class="text-muted-foreground">2x Studio Headphones</p> </div> </CollapsibleContent> </Collapsible> );}Installation
Usage
import { Collapsible, CollapsibleContent, CollapsibleTrigger,} from "~/components/ui/collapsible";<Collapsible> <CollapsibleTrigger>Can I use this in my project?</CollapsibleTrigger> <CollapsibleContent> Yes. Free to use for personal and commercial projects. No attribution required. </CollapsibleContent></Collapsible>Composition
Use the following composition to build a Collapsible:
Collapsible├── CollapsibleTrigger└── CollapsibleContentControlled State
Use the open and onOpenChange props to control the state.
import { createSignal } from "solid-js";
const [open, setOpen] = createSignal(false);
<Collapsible open={open()} onOpenChange={setOpen}> <CollapsibleTrigger>Toggle</CollapsibleTrigger> <CollapsibleContent>Content</CollapsibleContent></Collapsible>;Basic
import { ChevronDownIcon } from "lucide-solid";import { Button } from "~/components/ui/button";import { Card, CardContent } from "~/components/ui/card";import { Collapsible, CollapsibleContent, CollapsibleTrigger,} from "~/components/ui/collapsible";
export default function CollapsibleBasic() { return ( <Card class="mx-auto w-full max-w-sm"> <CardContent> <Collapsible class="rounded-md data-[expanded]:bg-muted"> <CollapsibleTrigger as={Button} variant="ghost" class="w-full"> Product details <ChevronDownIcon class="ml-auto transition-transform group-data-[expanded]:rotate-180" /> </CollapsibleTrigger> <CollapsibleContent class="flex flex-col items-start gap-2 p-2.5 pt-0 text-sm"> <div>This panel can be expanded or collapsed to reveal additional content.</div> <Button size="xs">Learn More</Button> </CollapsibleContent> </Collapsible> </CardContent> </Card> );}Settings Panel
Use a trigger button to reveal additional settings.
Radius
Set the corner radius of the element.
import { MaximizeIcon, MinimizeIcon } from "lucide-solid";import { createSignal, Show } from "solid-js";import { Button } from "~/components/ui/button";import { Card, CardContent, CardDescription, CardHeader, CardTitle,} from "~/components/ui/card";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 CollapsibleSettings() { const [open, setOpen] = createSignal(false);
return ( <Card class="mx-auto w-full max-w-xs" size="sm"> <CardHeader> <CardTitle>Radius</CardTitle> <CardDescription>Set the corner radius of the element.</CardDescription> </CardHeader> <CardContent> <Collapsible open={open()} onOpenChange={setOpen} class="flex items-start gap-2"> <FieldGroup class="grid w-full grid-cols-2 gap-2"> <Field> <FieldLabel for="collapsible-radius-x" class="sr-only"> Radius X </FieldLabel> <Input id="collapsible-radius-x" placeholder="0" value="0" /> </Field> <Field> <FieldLabel for="collapsible-radius-y" class="sr-only"> Radius Y </FieldLabel> <Input id="collapsible-radius-y" placeholder="0" value="0" /> </Field> <CollapsibleContent class="col-span-full grid grid-cols-subgrid gap-2"> <Field> <FieldLabel for="collapsible-radius-z" class="sr-only"> Radius Z </FieldLabel> <Input id="collapsible-radius-z" placeholder="0" value="0" /> </Field> <Field> <FieldLabel for="collapsible-radius-w" class="sr-only"> Radius W </FieldLabel> <Input id="collapsible-radius-w" placeholder="0" value="0" /> </Field> </CollapsibleContent> </FieldGroup> <CollapsibleTrigger as={Button} variant="outline" size="icon" aria-label="Toggle radius settings" > <Show when={open()} fallback={<MaximizeIcon />}> <MinimizeIcon /> </Show> </CollapsibleTrigger> </Collapsible> </CardContent> </Card> );}File Tree
Use nested collapsibles to build a file tree.
import { ChevronRightIcon, FileIcon, FolderIcon } from "lucide-solid";import { For, Show } from "solid-js";import { Button } from "~/components/ui/button";import { Card, CardContent, CardHeader } from "~/components/ui/card";import { Collapsible, CollapsibleContent, CollapsibleTrigger,} from "~/components/ui/collapsible";import { Tabs, TabsList, TabsTrigger } from "~/components/ui/tabs";
type FileTreeItem = { name: string; items?: FileTreeItem[] };
const fileTree: FileTreeItem[] = [ { name: "components", items: [ { name: "ui", items: [ { name: "button.tsx" }, { name: "card.tsx" }, { name: "dialog.tsx" }, { name: "input.tsx" }, { name: "select.tsx" }, { name: "table.tsx" }, ], }, { name: "login-form.tsx" }, { name: "register-form.tsx" }, ], }, { name: "lib", items: [{ name: "utils.ts" }, { name: "cn.ts" }, { name: "api.ts" }], }, { name: "hooks", items: [ { name: "use-media-query.ts" }, { name: "use-debounce.ts" }, { name: "use-local-storage.ts" }, ], }, { name: "types", items: [{ name: "index.d.ts" }, { name: "api.d.ts" }], }, { name: "public", items: [{ name: "favicon.ico" }, { name: "logo.svg" }, { name: "images" }], }, { name: "app.tsx" }, { name: "layout.tsx" }, { name: "globals.css" }, { name: "package.json" }, { name: "tsconfig.json" }, { name: "README.md" }, { name: ".gitignore" },];
function FileTreeItem(props: { item: FileTreeItem }) { return ( <Show when={props.item.items} fallback={ <Button variant="link" size="sm" class="w-full justify-start gap-2 text-foreground"> <FileIcon /> <span>{props.item.name}</span> </Button> } > {(items) => ( <Collapsible> <CollapsibleTrigger as={Button} variant="ghost" size="sm" class="group w-full justify-start transition-none hover:bg-accent hover:text-accent-foreground" > <ChevronRightIcon class="transition-transform group-data-[expanded]:rotate-90" /> <FolderIcon /> {props.item.name} </CollapsibleTrigger> <CollapsibleContent class="mt-1 ml-5"> <div class="flex flex-col gap-1"> <For each={items()}>{(item) => <FileTreeItem item={item} />}</For> </div> </CollapsibleContent> </Collapsible> )} </Show> );}
export default function CollapsibleFileTree() { return ( <Card class="mx-auto w-full max-w-[16rem] gap-2" size="sm"> <CardHeader> <Tabs defaultValue="explorer"> <TabsList class="w-full"> <TabsTrigger value="explorer">Explorer</TabsTrigger> <TabsTrigger value="settings">Outline</TabsTrigger> </TabsList> </Tabs> </CardHeader> <CardContent> <div class="flex flex-col gap-1"> <For each={fileTree}>{(item) => <FileTreeItem item={item} />}</For> </div> </CardContent> </Card> );}API Reference
For primitive props, keyboard behavior, and accessibility details, see the Kobalte Collapsible API reference.