Skip to content
Nerdfishui
Esc
navigateopen⌘Jpreview
On this page

Collapsible

An interactive component which expands/collapses a panel.

'use client'

import { Button } from '@nerdfish/react/button'
import {
	Collapsible,
	CollapsibleContent,
	CollapsibleTrigger,
} from '@nerdfish/react/collapsible'
import { ChevronsUpDown } from 'lucide-react'
import { useState } from 'react'

export default function CollapsibleExample() {
	const [isOpen, setIsOpen] = useState(false)

	return (
		<Collapsible
			open={isOpen}
			onOpenChange={setIsOpen}
			className="flex w-87.5 max-w-[calc(100vw-3rem)] flex-col gap-2"
		>
			<div className="flex items-center justify-between gap-4 px-4">
				<h4 className="text-sm font-semibold">
					Recent projects and repositories
				</h4>
				<CollapsibleTrigger
					render={
						<Button variant="ghost" size="xs" icon>
							<ChevronsUpDown />
							<span className="sr-only">Toggle</span>
						</Button>
					}
				/>
			</div>
			<div className="rounded-md border px-4 py-2 font-mono text-sm">
				nerdfish-ui/react
			</div>
			<CollapsibleContent className="flex flex-col gap-2">
				<div className="rounded-md border px-4 py-2 font-mono text-sm">
					@radix-ui/primitives
				</div>
				<div className="rounded-md border px-4 py-2 font-mono text-sm">
					@tailwindcss/forms
				</div>
				<div className="rounded-md border px-4 py-2 font-mono text-sm">
					@types/react
				</div>
			</CollapsibleContent>
		</Collapsible>
	)
}

Card Example

'use client'

import { Badge } from '@nerdfish/react/badge'
import { Button } from '@nerdfish/react/button'
import { Card, CardContent, CardHeader } from '@nerdfish/react/card'
import {
	Collapsible,
	CollapsibleContent,
	CollapsibleTrigger,
} from '@nerdfish/react/collapsible'
import { cn } from '@nerdfish/utils/class'
import { ArrowDown, ArrowUp, ChevronDown, ChevronUp } from 'lucide-react'
import { useState } from 'react'

export default function CollapsibleCardExample() {
	const [isOpen, setIsOpen] = useState(false)

	interface IStatItem {
		label: string
		value: number
		change: string
		changeType: 'increase' | 'decrease' // Type to define whether it's an increase or decrease
	}

	const stats: IStatItem[] = [
		{
			label: 'Added to Cart',
			value: 3842,
			change: '+1.8%',
			changeType: 'increase',
		},
		{
			label: 'Reached Checkout',
			value: 1256,
			change: '-1.2%',
			changeType: 'decrease',
		},
		{ label: 'Purchased', value: 649, change: '+2.4%', changeType: 'increase' },
	]

	return (
		<Card className="w-87.5 max-w-[calc(100vw-3rem)]">
			<Collapsible open={isOpen} onOpenChange={setIsOpen}>
				<CardHeader className="h-auto items-center gap-0">
					<div className="gap-friends flex items-center justify-between">
						<div>
							<div className="text-muted-foreground text-sm font-medium">
								Conversion Rate
							</div>
							<div className="flex items-center gap-1.5">
								<span className="text-foreground text-xl font-semibold">
									29.9%
								</span>
								<Badge appearance="outline" size="sm" shape="circle">
									+4,5%
								</Badge>
							</div>
						</div>
						<CollapsibleTrigger
							render={
								<Button variant="outline" size="sm">
									Details
									{isOpen ? <ChevronUp /> : <ChevronDown />}
								</Button>
							}
						/>
					</div>
				</CardHeader>
				<CollapsibleContent>
					<CardContent className="space-y-friends mt-friends text-sm">
						{stats.map((stat, index) => (
							<div key={index} className="flex items-center justify-between">
								<span className="text-muted-foreground">{stat.label}</span>
								<div className="flex items-center space-x-2">
									<span className="text-foreground font-semibold">
										${stat.value.toLocaleString()}
									</span>
									<span
										className={cn(
											'flex min-w-20 items-center justify-end text-sm font-medium',
											stat.changeType === 'increase'
												? 'text-success'
												: 'text-destructive',
										)}
									>
										{stat.changeType === 'increase' ? (
											<ArrowUp className="size-3.5" />
										) : (
											<ArrowDown className="size-3.5" />
										)}
										{stat.change}
									</span>
								</div>
							</div>
						))}
					</CardContent>
				</CollapsibleContent>
			</Collapsible>
		</Card>
	)
}