본문으로 건너뛰기
언어

Collapsiblestandard

하나의 영역을 펼치고 접는 접이식(collapsible)입니다. shadcn base-nova 의 원본을 그대로 담은 아이템이며 Base UI `Collapsible` 을 `data-slot` 만 붙여 감쌉니다. 스타일은 입히지 않습니다. 여러 항목 중 고르는 목록은 `accordion` 을 씁니다.

설치

pnpm
pnpm dlx shadcn@4.23.0 add @uikit/collapsible

Default

collapsible-example.tsx
"use client"
import * as React from "react"
import {  Example,  ExampleWrapper,} from "@/components/example"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"import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"import { ChevronRightIcon, FileIcon, FolderIcon, MaximizeIcon, MinimizeIcon } from "lucide-react"
export default function CollapsibleExample() {  return (    <ExampleWrapper>      <CollapsibleFileTree />      <CollapsibleSettings />    </ExampleWrapper>  )}
type FileTreeItem = { name: string } | { name: string; items: FileTreeItem[] }
function CollapsibleFileTree() {  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" },  ]
  const renderItem = (fileItem: FileTreeItem) => {    if ("items" in fileItem) {      return (        <Collapsible key={fileItem.name}>          <CollapsibleTrigger            render={              <Button                variant="ghost"                size="sm"                className="group w-full justify-start transition-none hover:bg-accent hover:text-accent-foreground"              />            }          >            <ChevronRightIcon className="transition-transform group-data-[state=open]:rotate-90" />            <FolderIcon />            {fileItem.name}          </CollapsibleTrigger>          <CollapsibleContent className="mt-1 ml-5 style-lyra:ml-4">            <div className="flex flex-col gap-1">              {fileItem.items.map((child) => renderItem(child))}            </div>          </CollapsibleContent>        </Collapsible>      )    }    return (      <Button        key={fileItem.name}        variant="link"        size="sm"        className="w-full justify-start gap-2 text-foreground"      >        <FileIcon />        <span>{fileItem.name}</span>      </Button>    )  }
  return (    <Example title="File Tree" className="items-center">      <Card className="mx-auto w-full max-w-[16rem] gap-2" size="sm">        <CardHeader>          <Tabs defaultValue="explorer">            <TabsList className="w-full">              <TabsTrigger value="explorer">Explorer</TabsTrigger>              <TabsTrigger value="settings">Outline</TabsTrigger>            </TabsList>          </Tabs>        </CardHeader>        <CardContent>          <div className="flex flex-col gap-1">            {fileTree.map((item) => renderItem(item))}          </div>        </CardContent>      </Card>    </Example>  )}
function CollapsibleSettings() {  const [isOpen, setIsOpen] = React.useState(false)
  return (    <Example title="Settings" className="items-center">      <Card className="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={isOpen}            onOpenChange={setIsOpen}            className="flex items-start gap-2"          >            <FieldGroup className="grid w-full grid-cols-2 gap-2">              <Field>                <FieldLabel htmlFor="radius-x" className="sr-only">                  Radius X                </FieldLabel>                <Input id="radius" placeholder="0" defaultValue={0} />              </Field>              <Field>                <FieldLabel htmlFor="radius-y" className="sr-only">                  Radius Y                </FieldLabel>                <Input id="radius" placeholder="0" defaultValue={0} />              </Field>              <CollapsibleContent className="col-span-full grid grid-cols-subgrid gap-2">                <Field>                  <FieldLabel htmlFor="radius-x" className="sr-only">                    Radius X                  </FieldLabel>                  <Input id="radius" placeholder="0" defaultValue={0} />                </Field>                <Field>                  <FieldLabel htmlFor="radius-y" className="sr-only">                    Radius Y                  </FieldLabel>                  <Input id="radius" placeholder="0" defaultValue={0} />                </Field>              </CollapsibleContent>            </FieldGroup>            <CollapsibleTrigger aria-label="Toggle details"              render={<Button variant="outline" size="icon" />}            >              {isOpen ? (                <MinimizeIcon />              ) : (                <MaximizeIcon />              )}            </CollapsibleTrigger>          </Collapsible>        </CardContent>      </Card>    </Example>  )}