Collapsible wrappers
Order #4189
StatusShipped
Shipping address100 Market St, San Francisco
Items2x Studio Headphones
import { Button } from '@/components/ui/button'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
...import { Button } from '@/components/ui/button'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
function ToggleIcon() { return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m7 15 5 5 5-5M7 9l5-5 5 5" /></svg> }
export default function CollapsibleDemoExample() {
let open = $state(false)
return (
<Collapsible open={open} onOpenChange={value => { open = value }} 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 asChild><Button variant="ghost" size="icon" class="size-8"><ToggleIcon /><span class="sr-only">Toggle details</span></Button></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
npx @fictjs/shadcn@latest add collapsibleInstall the runtime dependencies:
npm install @fictjs/radix-uiCopy the Fict shadcn component into your project.
Source
components/ui/collapsible.tsx
src/components/ui/collapsible.tsx
import { Collapsible as CollapsiblePrimitive } from '@fictjs/radix-ui'
import { cn } from '@/lib/cn'
export const Collapsible = CollapsiblePrimitive.Root
type GenericProps = {
class?: string
children?: unknown
[key: string]: unknown
}
export function CollapsibleTrigger(props: GenericProps) {
const { class: className, ...rest } = props
return <CollapsiblePrimitive.Trigger class={cn('inline-flex items-center justify-center text-sm font-medium', className)} {...rest} />
}
export function CollapsibleContent(props: GenericProps) {
const { class: className, ...rest } = props
return <CollapsiblePrimitive.Content class={cn('overflow-hidden text-sm', className)} {...rest} />
}
Usage
Examples
Basic
import { Button } from '@/components/ui/button'
import { Card, CardContent } from '@/components/ui/card'
...import { Button } from '@/components/ui/button'
import { Card, CardContent } from '@/components/ui/card'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
function ChevronDownIcon() { return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg> }
export default function CollapsibleBasicExample() {
return <Card class="w-full max-w-sm"><CardContent><Collapsible class="rounded-md data-[state=open]:bg-muted"><CollapsibleTrigger asChild><Button variant="ghost" class="group w-full">Product details<ChevronDownIcon /></Button></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
Radius
Set the corner radius of the element.
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
...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 { Input } from '@/components/ui/input'
function ExpandIcon() { return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3" /></svg> }
export default function CollapsibleSettingsExample() {
return <Card class="w-80"><CardHeader><CardTitle>Radius</CardTitle><CardDescription>Set the corner radius of the element.</CardDescription></CardHeader><CardContent><Collapsible class="flex items-start gap-2"><div class="grid flex-1 grid-cols-2 gap-2"><Input aria-label="Radius X" value="0" /><Input aria-label="Radius Y" value="0" /><CollapsibleContent class="col-span-2 grid grid-cols-2 gap-2"><Input aria-label="Radius X expanded" value="0" /><Input aria-label="Radius Y expanded" value="0" /></CollapsibleContent></div><CollapsibleTrigger asChild><Button variant="outline" size="icon" aria-label="Expand radius controls"><ExpandIcon /></Button></CollapsibleTrigger></Collapsible></CardContent></Card>
}
File Tree
import { Card, CardContent, CardHeader } from '@/components/ui/card'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
...import { Card, CardContent, CardHeader } from '@/components/ui/card'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
const files = ['app.tsx', 'layout.tsx', 'globals.css', 'package.json', 'tsconfig.json', 'README.md', '.gitignore']
function FileIcon() { return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zM14 2v6h6" /></svg> }
export default function CollapsibleFileTreeExample() {
return <Card class="w-64"><Tabs defaultValue="explorer"><CardHeader><TabsList><TabsTrigger value="explorer">Explorer</TabsTrigger><TabsTrigger value="outline">Outline</TabsTrigger></TabsList></CardHeader><CardContent><TabsContent value="explorer" class="grid gap-1">{files.map(file => <button type="button" class="flex items-center gap-2"><FileIcon />{file}</button>)}</TabsContent><TabsContent value="outline">No symbols found.</TabsContent></CardContent></Tabs></Card>
}
Rtl
الطلب #4189
الحالةتم الشحن
عنوان الشحن100 Market St, San Francisco
العناصر2x سماعات الاستوديو
import { Button } from '@/components/ui/button'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
...import { Button } from '@/components/ui/button'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
const translations = {
ar: { order: 'الطلب #4189', status: 'الحالة', shipped: 'تم الشحن', addressTitle: 'عنوان الشحن', address: '100 Market St, San Francisco', items: 'العناصر', item: '2x سماعات الاستوديو' },
he: { order: 'הזמנה #4189', status: 'סטטוס', shipped: 'נשלח', addressTitle: 'כתובת משלוח', address: '100 Market St, San Francisco', items: 'פריטים', item: '2x אוזניות סטודיו' },
en: { order: 'Order #4189', status: 'Status', shipped: 'Shipped', addressTitle: 'Shipping address', address: '100 Market St, San Francisco', items: 'Items', item: '2x Studio Headphones' },
} as const
function ToggleIcon() { return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m7 15 5 5 5-5M7 9l5-5 5 5" /></svg> }
export default function CollapsibleRtlExample() {
let language = $state<keyof typeof translations>('ar')
let open = $state(false)
const direction = () => language === 'en' ? 'ltr' : 'rtl'
const text = () => translations[language]
return <div class="grid gap-4"><select value={language} onChange={event => { language = event.currentTarget.value as keyof typeof translations }}><option value="ar">Arabic (العربية)</option><option value="he">Hebrew (עברית)</option><option value="en">English</option></select><Collapsible open={open} onOpenChange={value => { open = value }} class="flex w-[350px] flex-col gap-2" dir={direction()}><div class="flex items-center justify-between gap-4 px-4"><h4 class="text-sm font-semibold">{text().order}</h4><CollapsibleTrigger asChild><Button variant="ghost" size="icon" class="size-8"><ToggleIcon /><span class="sr-only">Toggle details</span></Button></CollapsibleTrigger></div><div class="flex items-center justify-between rounded-md border px-4 py-2 text-sm"><span>{text().status}</span><strong>{text().shipped}</strong></div><CollapsibleContent class="flex flex-col gap-2"><div class="rounded-md border px-4 py-2 text-sm"><strong>{text().addressTitle}</strong><p>{text().address}</p></div><div class="rounded-md border px-4 py-2 text-sm"><strong>{text().items}</strong><p>{text().item}</p></div></CollapsibleContent></Collapsible></div>
}