useAccordion
Hooks that manage accordion state, keyboard navigation, and ARIA attributes.
Usage#
import { useAccordion, useAccordionPanel } from '@primereact/headless/accordion';
const accordion = useAccordion({ defaultValue: '1' });
const { rootProps } = accordion;
const { panelProps, headerProps, triggerProps, contentProps, indicatorProps, state } = useAccordionPanel({
value: '1',
context: accordion
});
return (
<div {...rootProps}>
<div {...panelProps}>
<div {...headerProps}>
<button {...triggerProps}>
<span {...indicatorProps} />
</button>
</div>
{state.open && <div {...contentProps}></div>}
</div>
</div>
);useAccordion manages root state while useAccordionPanel consumes that context to return prop objects for each panel element — see Primitive for a component-based API.
Features#
- Two-hook architecture:
useAccordionfor root state,useAccordionPanelfor per-panel behavior - Returns spread-ready prop objects (
rootProps,panelProps,triggerProps,contentProps,headerProps,indicatorProps) - Controlled and uncontrolled value management
- Single or multiple panel expansion
- Exposes
state,updateValue, andisItemActivefor custom logic openOnFocusoption for focus-triggered expansion
Behavior#
Default Value#
Use defaultValue to set initially expanded panels.
const accordion = useAccordion({ defaultValue: '1' });Controlled#
Use value and onValueChange for full programmatic control. The hook never updates its own state in controlled mode.
const [value, setValue] = React.useState<string | null>('1');
const accordion = useAccordion({
value,
onValueChange: (e) => setValue(e.value)
});The onValueChange callback receives { originalEvent, value } where value is the new active panel key (or array in multiple mode).
Multiple#
Set multiple to allow multiple panels to be open simultaneously. In this mode, value/defaultValue accepts an array.
const accordion = useAccordion({ multiple: true, defaultValue: ['1', '2'] });Disabled#
Set disabled on the root to disable all panels, or pass disabled to individual useAccordionPanel calls.
// Disable all panels
const accordion = useAccordion({ disabled: true });
// Disable a specific panel
const panel = useAccordionPanel({ value: '2', disabled: true, context: accordion });When disabled, triggerProps sets tabIndex to -1, adds aria-disabled, and suppresses onClick/onKeyDown handlers.
Open on Focus#
Set openOnFocus to expand panels when their trigger receives focus via keyboard navigation (Arrow keys, Home, End).
const accordion = useAccordion({ openOnFocus: true });Using updateValue and isItemActive#
The hook exposes imperative methods for custom logic outside the standard trigger flow.
const accordion = useAccordion({ multiple: true });
// Programmatically open a panel
accordion.updateValue(syntheticEvent, '3');
// Check if a panel is active
if (accordion.isItemActive('2')) {
// ...
}In single mode, updateValue toggles between the key and null. In multiple mode, it adds or removes the key from the array.
Conditional Rendering with state.open#
Unlike the primitive component, the headless hook gives you full control over whether content is rendered. Use state.open to conditionally mount or unmount content.
const { contentProps, state } = useAccordionPanel({ value: '1', context: accordion });
{
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>For animated enter/leave transitions, use the useMotion hook alongside state.open.
Custom Styling with Data Attributes#
Every prop object includes data-scope="accordion" and a data-part attribute. State-dependent attributes (data-open, data-closed, data-disabled) are added automatically.
[data-scope='accordion'][data-part='trigger'] {
font-weight: 600;
}
[data-scope='accordion'][data-part='content'][data-open] {
animation: slideDown 200ms ease-out;
}
[data-scope='accordion'][data-part='content'][data-closed] {
animation: slideUp 200ms ease-out;
}
[data-scope='accordion'][data-part='panel'][data-disabled] {
opacity: 0.5;
}triggerProps also includes data-content-open/data-content-closed for styling the trigger based on content state.
[data-scope='accordion'][data-part='trigger'][data-content-open] {
color: blue;
font-weight: 700;
}
[data-scope='accordion'][data-part='trigger'][data-content-closed] {
color: inherit;
font-weight: 400;
}API#
useAccordion#
| Name | Type | Default |
|---|---|---|
defaultValue | string | number | (string | number)[] | — |
| Default value of the active panel or an array of values in multiple mode. | ||
value | string | number | (string | number)[] | — |
| Value of the active panel or an array of values in multiple mode. | ||
multiple | boolean | false |
| When enabled, multiple tabs can be activated at the same time. | ||
disabled | boolean | false |
| When disabled, the component cannot be interacted with. | ||
tabIndex | number | 0 |
| Index of the element in tabbing order. | ||
openOnFocus | boolean | false |
| When enabled, the accordion panel will be opened on focus. | ||
onValueChange | (event: useAccordionChangeEvent) => void | — |
| Callback fired when the accordion's value changes. | ||
useAccordionPanel#
| Name | Type | Default |
|---|---|---|
value | string | number | — |
| Unique value of the panel. | ||
disabled | boolean | false |
| Whether the panel is disabled. | ||
context | useAccordionInstance | — |
| The parent accordion instance providing state and methods. | ||
Accessibility#
See Accordion Primitive for WAI-ARIA compliance details and keyboard support.