Collapsible
A disclosure control that opens and closes a single panel of content.
API Reference
Original primitive API
Behavior, accessibility details, and low-level props are documented by Base UI.
Basic
import { Collapsible, CollapsibleTrigger, CollapsiblePanel,} from "moduix";export function CollapsibleDemo() { return ( <Collapsible className={styles.root}> <CollapsibleTrigger>Recovery keys</CollapsibleTrigger> <CollapsiblePanel> <ul className={styles.keysList}> {recoveryKeys.map((key) => ( <li key={key}>{key}</li> ))} </ul> </CollapsiblePanel> </Collapsible> );}.root { width: 16rem;}.keysList { display: flex; flex-direction: column; gap: var(--spacing-1); margin: 0; padding-inline-start: var(--spacing-5);}const recoveryKeys = ["alien-bean-pasta", "wild-irish-burrito", "horse-battery-staple"];Full list of component variables available for project-level overrides.
| Property | Default | Description |
|---|---|---|
| --collapsible-color | var(--color-foreground) | Controls root text color. |
| --collapsible-disabled-opacity | var(--opacity-disabled) | Controls disabled opacity. |
| --collapsible-focus-ring-color | var(--color-ring) | Controls trigger focus ring color. |
| --collapsible-focus-ring-offset | var(--border-width-sm) | Controls trigger focus ring offset. |
| --collapsible-focus-ring-width | var(--border-width-sm) | Controls trigger focus ring width. |
| --collapsible-icon-open-transform | rotate(90deg) | Controls icon transform when the panel is open. |
| --collapsible-icon-size | 0.75rem | Controls trigger icon size. |
| --collapsible-icon-transition | var(--transition-default) | Controls icon transition. |
| --collapsible-panel-color | var(--color-muted-foreground) | Controls panel text color. |
| --collapsible-panel-font-size | var(--text-sm) | Controls panel font size. |
| --collapsible-panel-line-height | var(--line-height-text-sm) | Controls panel line height. |
| --collapsible-panel-transition | var(--transition-default) | Controls panel open and close transition. |
| --collapsible-trigger-bg | transparent | Controls trigger background color. |
| --collapsible-trigger-bg-active | var(--collapsible-trigger-bg-hover) | Controls trigger background color while pressed. |
| --collapsible-trigger-bg-hover | var(--collapsible-trigger-bg) | Controls trigger background color on hover. |
| --collapsible-trigger-color | var(--collapsible-color) | Controls trigger text color. |
| --collapsible-trigger-font-size | var(--text-sm) | Controls trigger font size. |
| --collapsible-trigger-gap | var(--spacing-2) | Controls trigger content gap. |
| --collapsible-trigger-line-height | var(--line-height-text-sm) | Controls trigger line height. |
| --collapsible-trigger-padding-x | 0 | Controls trigger horizontal padding. |
| --collapsible-trigger-padding-y | 0 | Controls trigger vertical padding. |
| --collapsible-trigger-radius | 0 | Controls trigger corner radius. |
| --collapsible-trigger-transition | var(--transition-default) | Controls trigger color and background transition. |
Interactive variables scoped for docs preview without changing size scale tokens.
| Property | Value | Default | Description |
|---|---|---|---|
| --collapsible-color | var(--color-foreground) | Controls root text color. | |
| --collapsible-disabled-opacity | var(--opacity-disabled) | Controls disabled opacity. | |
| --collapsible-focus-ring-color | var(--color-ring) | Controls trigger focus ring color. | |
| --collapsible-focus-ring-offset | var(--border-width-sm) | Controls trigger focus ring offset. | |
| --collapsible-focus-ring-width | var(--border-width-sm) | Controls trigger focus ring width. | |
| --collapsible-icon-open-transform | rotate(90deg) | Controls icon transform when the panel is open. | |
| --collapsible-icon-size | 0.75rem | Controls trigger icon size. | |
| --collapsible-icon-transition | var(--transition-default) | Controls icon transition. | |
| --collapsible-panel-color | var(--color-muted-foreground) | Controls panel text color. | |
| --collapsible-panel-font-size | var(--text-sm) | Controls panel font size. | |
| --collapsible-panel-line-height | var(--line-height-text-sm) | Controls panel line height. | |
| --collapsible-panel-transition | var(--transition-default) | Controls panel open and close transition. | |
| --collapsible-trigger-bg | transparent | Controls trigger background color. | |
| --collapsible-trigger-bg-active | var(--collapsible-trigger-bg-hover) | Controls trigger background color while pressed. | |
| --collapsible-trigger-bg-hover | var(--collapsible-trigger-bg) | Controls trigger background color on hover. | |
| --collapsible-trigger-color | var(--collapsible-color) | Controls trigger text color. | |
| --collapsible-trigger-font-size | var(--text-sm) | Controls trigger font size. | |
| --collapsible-trigger-gap | var(--spacing-2) | Controls trigger content gap. | |
| --collapsible-trigger-line-height | var(--line-height-text-sm) | Controls trigger line height. | |
| --collapsible-trigger-padding-x | 0 | Controls trigger horizontal padding. | |
| --collapsible-trigger-padding-y | 0 | Controls trigger vertical padding. | |
| --collapsible-trigger-radius | 0 | Controls trigger corner radius. | |
| --collapsible-trigger-transition | var(--transition-default) | Controls trigger color and background transition. |
Anatomy
Collapsible groups one toggle control and one panel that share the same open state.
Keep CollapsibleTrigger and CollapsiblePanel inside the same root so keyboard and
accessibility wiring stay connected.
Collapsible
├─ CollapsibleTrigger
│ └─ label
└─ CollapsiblePanel
└─ content<Collapsible>
<CollapsibleTrigger>Recovery keys</CollapsibleTrigger>
<CollapsiblePanel>
<div className={styles.panelContent}>Store these keys somewhere safe.</div>
</CollapsiblePanel>
</Collapsible>| Part | Role |
|---|---|
Collapsible | Root state machine. Controls open, defaultOpen, disabled, and onOpenChange. |
CollapsibleTrigger | Interactive toggle button. Opens or closes the panel, receives open/disabled attributes, and renders an icon. |
CollapsibleTriggerIcon | Advanced visual state marker. Use directly only when manually composing trigger contents. |
CollapsiblePanel | Collapsible content region. Put spacing/surface wrappers inside it for cleaner animations. |
CollapsibleTrigger renders its icon internally so the common composition stays compact.
Use icon, hideIcon, classNames.icon, and slotProps.icon when you need to replace,
remove, style, or pass props to that internal slot. CollapsibleTriggerIcon is still exported
for advanced manual composition, but most projects do not need it.
Collapsible does not use service slots like portal, backdrop, or viewport. In most cases,
keep the default structure and customize visible parts: the root, trigger, icon slot, panel,
and content wrapper inside the panel.
Composition
Use Collapsible for root state and behavior props such as open, defaultOpen,
onOpenChange, and disabled.
All parts in this component are visible slots. Style Collapsible, CollapsibleTrigger,
and CollapsiblePanel directly with className. Use classNames.icon for the icon rendered
inside CollapsibleTrigger, or compose CollapsibleTriggerIcon manually when you need full
control over trigger children. All Base UI behavior props such as render, nativeButton,
keepMounted, and hiddenUntilFound pass through to the matching primitive part.
Examples
Default Open
Use defaultOpen when the panel should be expanded on first render.
- alien-bean-pasta
- wild-irish-burrito
- horse-battery-staple
import { Collapsible, CollapsibleTrigger, CollapsiblePanel,} from "moduix";export function DefaultOpenCollapsibleDemo() { return ( <Collapsible defaultOpen className={styles.root}> <CollapsibleTrigger>Recovery keys</CollapsibleTrigger> <CollapsiblePanel> <ul className={styles.keysList}> {recoveryKeys.map((key) => ( <li key={key}>{key}</li> ))} </ul> </CollapsiblePanel> </Collapsible> );}.root { width: 16rem;}.keysList { display: flex; flex-direction: column; gap: var(--spacing-1); margin: 0; padding-inline-start: var(--spacing-5);}const recoveryKeys = ["alien-bean-pasta", "wild-irish-burrito", "horse-battery-staple"];Controlled
Control open from React state when the collapsible needs to coordinate with other UI.
import { Collapsible, CollapsibleTrigger, CollapsiblePanel,} from "moduix";import { useState } from "react";export function ControlledCollapsibleDemo() { const [open, setOpen] = useState(false); return ( <Collapsible open={open} onOpenChange={setOpen} className={styles.root}> <CollapsibleTrigger>Recovery keys</CollapsibleTrigger> <CollapsiblePanel> <ul className={styles.keysList}> {recoveryKeys.map((key) => ( <li key={key}>{key}</li> ))} </ul> </CollapsiblePanel> <span className={styles.status}>Current state: {open ? "open" : "closed"}</span> </Collapsible> );}.root { width: 16rem;}.keysList { display: flex; flex-direction: column; gap: var(--spacing-1); margin: 0; padding-inline-start: var(--spacing-5);}.status { margin-top: var(--spacing-2); color: var(--color-muted-foreground); font-size: var(--text-xs); line-height: var(--line-height-text-xs);}const recoveryKeys = ["alien-bean-pasta", "wild-irish-burrito", "horse-battery-staple"];Disabled
Set disabled on the root when the trigger should be visible but unavailable for interaction.
import { Collapsible, CollapsibleTrigger, CollapsiblePanel,} from "moduix";export function DisabledCollapsibleDemo() { return ( <Collapsible disabled className={styles.root}> <CollapsibleTrigger>Recovery keys</CollapsibleTrigger> <CollapsiblePanel> <ul className={styles.keysList}> {recoveryKeys.map((key) => ( <li key={key}>{key}</li> ))} </ul> </CollapsiblePanel> </Collapsible> );}.root { width: 16rem;}.keysList { display: flex; flex-direction: column; gap: var(--spacing-1); margin: 0; padding-inline-start: var(--spacing-5);}const recoveryKeys = ["alien-bean-pasta", "wild-irish-burrito", "horse-battery-staple"];Hidden Until Found
Use hiddenUntilFound when browser page search should be able to find and expand hidden panel content.
- alien-bean-pasta
- wild-irish-burrito
- horse-battery-staple
import { Collapsible, CollapsibleTrigger, CollapsiblePanel,} from "moduix";export function HiddenUntilFoundCollapsibleDemo() { return ( <Collapsible className={styles.root}> <CollapsibleTrigger>Searchable recovery keys</CollapsibleTrigger> <CollapsiblePanel hiddenUntilFound> <ul className={styles.keysList}> {recoveryKeys.map((key) => ( <li key={key}>{key}</li> ))} </ul> </CollapsiblePanel> </Collapsible> );}.root { width: 16rem;}.keysList { display: flex; flex-direction: column; gap: var(--spacing-1); margin: 0; padding-inline-start: var(--spacing-5);}const recoveryKeys = ["alien-bean-pasta", "wild-irish-burrito", "horse-battery-staple"];Custom Icon And Styles
Pass icon to replace the default visual marker and style it with classNames.icon.
Use className on the root, trigger, and panel slots when styling with CSS Modules,
Tailwind CSS, or CSS-in-JS. Put your own wrapper inside the panel when the content needs
layout or surface styles.
import { Collapsible, CollapsibleTrigger, CollapsiblePanel, ChevronDownIcon,} from "moduix";export function CustomStylesCollapsibleDemo() { return ( <Collapsible className={styles.customRoot}> <CollapsibleTrigger className={styles.customTrigger} icon={<ChevronDownIcon />} classNames={{ icon: styles.customTriggerIcon }} > Styled recovery keys </CollapsibleTrigger> <CollapsiblePanel className={styles.customPanel}> <div className={styles.customPanelContent}> <ul className={styles.keysList}> {recoveryKeys.map((key) => ( <li key={key}>{key}</li> ))} </ul> </div> </CollapsiblePanel> </Collapsible> );}.customRoot { width: 16rem; color: var(--color-foreground);}.customTrigger { padding: var(--spacing-2) var(--spacing-3); border-radius: var(--radius-md); background-color: var(--color-muted); color: var(--color-foreground);}@media (hover: hover) { .customTrigger:hover { background-color: var(--color-accent); }}.customTriggerIcon { --collapsible-icon-open-transform: rotate(180deg); color: var(--color-primary);}.customPanel { color: var(--color-muted-foreground);}.customPanelContent { margin-top: var(--spacing-1); padding: var(--spacing-2) var(--spacing-3); border-radius: var(--radius-md); background-color: var(--color-muted);}.keysList { display: flex; flex-direction: column; gap: var(--spacing-1); margin: 0; padding-inline-start: var(--spacing-5);}const recoveryKeys = ["alien-bean-pasta", "wild-irish-burrito", "horse-battery-staple"];