useCollapsible
Hook that manages open/close state, toggle behavior, and ARIA attributes for collapsible content.
Usage#
import { useCollapsible } from '@primereact/headless/collapsible';const { rootProps, triggerProps, contentProps, state } = useCollapsible();
<div {...rootProps}>
<button {...triggerProps}></button>
{state.open && <div {...contentProps}></div>}
</div>;useCollapsible manages open/close state with toggle, open, and close methods — see Primitive for a component-based API.
Features#
- Open/close state machine — tracks a single boolean with matching
aria-expanded,aria-controls, and data attributes - Controlled or uncontrolled — use
open/onOpenChangeexternally or rely ondefaultOpen - Imperative controls —
toggle(),open(), andclose()flip state from anywhere outside the trigger - Lifecycle callbacks —
onOpenandonClosefire alongsideonOpenChangefor per-direction side effects - Primitive for other hooks — the building block that
usePanel,useFieldset, and others wrap
Working with callbacks#
Controlled open state#
Drive open state from parent state with open and onOpenChange.
const [isOpen, setIsOpen] = React.useState(true);
const { state } = useCollapsible({
open: isOpen,
onOpenChange: (e) => setIsOpen(e.value)
});Directional callbacks#
When you only care about one direction, use onOpen or onClose instead of branching inside onOpenChange.
useCollapsible({
onOpen: () => analytics.track('panel_expanded'),
onClose: () => analytics.track('panel_collapsed')
});Imperative control from outside the trigger#
Expose toggle, open, and close on a ref or context so sibling UI can drive the panel.
const collapsible = useCollapsible({ defaultOpen: false });
<button onClick={(e) => collapsible.open(e)}>Expand</button>
<button onClick={(e) => collapsible.close(e)}>Collapse</button>Composing into higher-level hooks#
useCollapsible is the primitive that higher-level hooks build on — wrap it to create your own collapsible surface with extra behavior.
function useDisclosurePanel(options) {
const collapsible = useCollapsible(options);
const [loaded, setLoaded] = React.useState(false);
return {
...collapsible,
loaded,
onOpen: () => setLoaded(true) // load data the first time it opens
};
}Styling with data attributes#
The prop objects include data-scope="collapsible" and data-part. State is reflected via data-open/data-closed on root and content, and data-content-open/data-content-closed on the trigger.
[data-scope='collapsible'][data-part='root'][data-open] {
border-color: var(--p-primary-color);
}
[data-scope='collapsible'][data-part='trigger'][data-content-open] svg {
transform: rotate(180deg);
}API#
useCollapsible#
| Name | Type | Default |
|---|---|---|
open | boolean | false |
| Controls the open state of the collapsible. | ||
defaultOpen | boolean | false |
| Defines the initial open state of the collapsible. | ||
disabled | boolean | false |
| When disabled, the component cannot be interacted with. | ||
tabIndex | number | 0 |
| Index of the element in tabbing order. | ||
onOpen | (event?: SyntheticEvent) => void | — |
| Callback triggered when the content is opened. | ||
onClose | (event?: SyntheticEvent) => void | — |
| Callback triggered when the content is closed. | ||
onOpenChange | (event: useCollapsibleOpenChangeEvent) => void | — |
| Callback triggered when the content's toggle state changes. | ||
Accessibility#
Enter or Space on the trigger toggles the content, and the trigger exposes aria-expanded state. See Primitive for full WAI-ARIA compliance details.