Introducing PrimeReact v11-alpha 🎉Discover Now

usePanel

Hook that manages collapsible panel state and ARIA attributes.

Header
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
basic-demo

Usage#

import { usePanel } from '@primereact/headless/panel';
 
const { rootProps, triggerProps, contentProps, indicatorProps, state } = usePanel({ defaultOpen: true });
 
return (
    <div {...rootProps}>
        <button {...triggerProps}>
            <span {...indicatorProps} />
        </button>
        {state.open && <div {...contentProps}></div>}
    </div>
);

usePanel wraps useCollapsible and returns spread-ready prop objects for each DOM element — see Primitive for a component-based API.

Features#

  • Single-hook architecture built on useCollapsible
  • Returns spread-ready prop objects (rootProps, triggerProps, contentProps, indicatorProps)
  • Controlled and uncontrolled open state management
  • Exposes toggle, open, and close methods for imperative control

Behavior#

Default Open#

Use defaultOpen to set the initial open state.

const panel = usePanel({ defaultOpen: true });

Controlled#

Use open and onOpenChange for full programmatic control. The hook never updates its own state in controlled mode.

const [open, setOpen] = React.useState(true);
const panel = usePanel({
    open,
    onOpenChange: (e) => setOpen(e.value ?? false)
});

The onOpenChange callback receives { originalEvent, value } where value is the new boolean state.

Disabled#

Set disabled to prevent interaction. When disabled, triggerProps sets tabIndex to -1, adds aria-disabled, and suppresses onClick.

const panel = usePanel({ disabled: true });

Using toggle, open, and close#

The hook exposes imperative methods for custom logic outside the standard trigger flow.

const panel = usePanel({ defaultOpen: false });
 
// Open programmatically
panel.open(syntheticEvent);
 
// Close programmatically
panel.close(syntheticEvent);
 
// Toggle
panel.toggle(syntheticEvent);

Conditional Rendering with state.open#

Use state.open to conditionally mount or unmount content.

const { contentProps, state } = usePanel({ defaultOpen: true });
 
{
    state.open && <div {...contentProps}>Panel content — only in DOM when open</div>;
}

Alternatively, always render content and use CSS to show/hide:

<div {...contentProps} style={{ display: state.open ? 'block' : 'none' }}>
    Panel content — always in DOM, toggled with CSS
</div>

Custom Styling with Data Attributes#

Every prop object includes data-scope="panel" and a data-part attribute. State-dependent attributes (data-open, data-closed, data-disabled) are added automatically.

[data-scope='panel'][data-part='trigger'] {
    font-weight: 600;
}
 
[data-scope='panel'][data-part='content'][data-open] {
    animation: slideDown 200ms ease-out;
}
 
[data-scope='panel'][data-part='content'][data-closed] {
    animation: slideUp 200ms ease-out;
}

triggerProps also includes data-content-open/data-content-closed for styling the trigger based on content state.

[data-scope='panel'][data-part='trigger'][data-content-open] {
    color: blue;
}

API#

usePanel#

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: usePanelOpenChangeEvent) => void—
Callback triggered when the content's toggle state changes.

Accessibility#

See Panel Primitive for WAI-ARIA compliance details and keyboard support.