Introducing PrimeReact v11-alpha 🎉Discover Now

useCollapsible

Hook that manages open/close state, toggle behavior, and ARIA attributes for collapsible content.

basic-demo

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/onOpenChange externally or rely on defaultOpen
  • Imperative controls — toggle(), open(), and close() flip state from anywhere outside the trigger
  • Lifecycle callbacks — onOpen and onClose fire alongside onOpenChange for 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#

NameTypeDefault
openbooleanfalse
Controls the open state of the collapsible.
defaultOpenbooleanfalse
Defines the initial open state of the collapsible.
disabledbooleanfalse
When disabled, the component cannot be interacted with.
tabIndexnumber0
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.