Installation
pnpm dlx shadcn@latest add https://rdf.dev.360online.com/r/collapsible.jsonInstalls to @/components/ui/collapsible.
Manual installation
Install the dependencies:
pnpm add @base-ui/react@^1.8.0Copy the source into your project:
'use client'
import { Collapsible as CollapsiblePrimitive } from '@base-ui/react/collapsible'
function Collapsible({ ...props }: CollapsiblePrimitive.Root.Props) {
return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />
}
function CollapsibleTrigger({ ...props }: CollapsiblePrimitive.Trigger.Props) {
return <CollapsiblePrimitive.Trigger data-slot="collapsible-trigger" {...props} />
}
function CollapsibleContent({ ...props }: CollapsiblePrimitive.Panel.Props) {
return <CollapsiblePrimitive.Panel data-slot="collapsible-content" {...props} />
}
export { Collapsible, CollapsibleTrigger, CollapsibleContent }An interactive component which expands and collapses a panel. Built on top of Base UI Collapsible, it follows WAI-ARIA design patterns.
The components are unstyled wrappers around the Base UI primitives that add data-slot attributes
(collapsible, collapsible-trigger, collapsible-content). Style the trigger yourself, usually by
passing a Button to the render prop.
Features
- Controlled (
open/onOpenChange) and uncontrolled (defaultOpen) modes - Disabled state
renderprop on the trigger for composing withButtonor any other elementdata-panel-openon the trigger anddata-open/data-closedon the content for styling, for example rotating a chevron- Nested collapsibles support
- Keyboard navigation and screen reader support
Usage
import { ChevronsUpDownIcon } from 'lucide-react'
import { Button } from '@/components/ui/button'
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from '@/components/ui/collapsible'
export function MyCollapsible() {
return (
<Collapsible className="flex flex-col gap-2">
<div className="flex items-center justify-between">
<h4 className="text-sm font-medium">Case 2026-04812 has 4 attachments</h4>
<CollapsibleTrigger render={<Button variant="ghost" size="icon-sm" aria-label="Show all attachments" />}>
<ChevronsUpDownIcon />
</CollapsibleTrigger>
</div>
<CollapsibleContent>
<p>Site plan, Storgatan 14.pdf</p>
</CollapsibleContent>
</Collapsible>
)
}
// Controlled usage
export function ControlledCollapsible() {
const [isOpen, setIsOpen] = React.useState(false)
return (
<Collapsible open={isOpen} onOpenChange={setIsOpen}>
<CollapsibleTrigger render={<Button variant="outline" />}>{isOpen ? 'Hide case history' : 'Show case history'}</CollapsibleTrigger>
<CollapsibleContent>
<p>Application received via e-service, 2 April 2026</p>
</CollapsibleContent>
</Collapsible>
)
}Rotating Icon
The trigger gets data-panel-open when expanded, so you can rotate an icon with a group class:
<CollapsibleTrigger render={<Button variant="ghost" className="group" />}>
Open today 10:00–19:00
<ChevronDownIcon className="transition-transform group-data-panel-open:rotate-180" />
</CollapsibleTrigger>Examples
Default
A list of case attachments where only the first is shown until the icon button is pressed.
With Icon
A full-width trigger with a leading icon and a rotating chevron, revealing a library's opening hours.
Controlled Example
The case history in a Card, controlled with open and onOpenChange so the trigger label can follow the state.
Disabled
A disabled collapsible cannot be toggled. Say why in the trigger.
Nested Collapsibles
Nested collapsibles used to build an archive tree.
Props
Collapsible
open- The controlled open statedefaultOpen- The default open stateonOpenChange- Event handler for open state changes,(open, eventDetails) => voiddisabled- Whether the collapsible is disabled
CollapsibleTrigger
render- The element to render instead of abutton, e.g.render={<Button variant="outline" />}children- Content to display in the triggerclassName- Additional CSS classes
The trigger renders no icon of its own; add one yourself.
CollapsibleContent
keepMounted- Keep the content mounted when closedhiddenUntilFound- Keep closed content findable with the browser's find-in-page, which opens the panel on a matchchildren- Content to display when expandedclassName- Additional CSS classes
Accessibility
The Collapsible component follows WAI-ARIA guidelines:
- Uses proper ARIA roles (
button,region) - Supports keyboard navigation:
Space/Enter: Toggle expansionTab: Navigate to trigger
- Announces state changes to screen readers
- Maintains focus management
- Provides visual feedback for interaction states
Best Practices
-
Content Organization:
- Keep content concise and focused
- Use clear trigger text
- Consider content hierarchy
- Group related information
-
Visual Design:
- Maintain consistent spacing
- Use clear visual indicators
- Provide feedback for state changes
- Consider mobile touch targets
-
Interaction:
- Keep animations smooth
- Handle focus properly
- Consider loading states
- Manage nested collapsibles
-
Implementation:
- Use semantic markup
- Handle state changes gracefully
- Consider performance
- Test edge cases
Related Components
- Accordion
- Drawer