Accordion groups a collection of contents in panels.
import { Accordion } from 'primereact/accordion';
<Accordion>
<Accordion.Panel value="1">
<Accordion.Header>
Title
<Accordion.HeaderIndicator />
</Accordion.Header>
<Accordion.Content>Content</Accordion.Content>
</Accordion.Panel>
</Accordion>
Accordion is defined using Accordion
, Accordion.Panel
, Accordion.Header
, Accordion.HeaderIndicator
and Accordion.Content
components. Each Accordion.Panel
must contain a unique value
property to specify the active item.
import { Accordion } from 'primereact/accordion';
export default function BasicDemo() {
return (
<div className="card">
<Accordion className="max-w-md mx-auto">
<Accordion.Panel value="1">
<Accordion.Header>
What is this service about?
<Accordion.HeaderIndicator />
</Accordion.Header>
<Accordion.Content>
<p>This service helps you manage your projects more efficiently by offering real-time collaboration, task tracking, and powerful analytics. Whether you’re working solo or in a team, it’s built to scale with your needs.</p>
</Accordion.Content>
</Accordion.Panel>
<Accordion.Panel value="2">
<Accordion.Header>
Is my data secure?
<Accordion.HeaderIndicator />
</Accordion.Header>
<Accordion.Content>
<p>Yes. We use end-to-end encryption and follow industry best practices to ensure your data is protected. Your information is stored on secure servers and regularly backed up.</p>
</Accordion.Content>
</Accordion.Panel>
<Accordion.Panel value="3">
<Accordion.Header>
Can I upgrade or downgrade my plan later?
<Accordion.HeaderIndicator />
</Accordion.Header>
<Accordion.Content>
<p>Absolutely. You can change your subscription plan at any time from your account settings. Changes take effect immediately, and any billing adjustments are handled automatically.</p>
</Accordion.Content>
</Accordion.Panel>
</Accordion>
</div>
);
}
Only one tab at a time can be active by default, enabling multiple
property changes this behavior to allow multiple panels. In this case multiple
needs to be an array.
import { Accordion } from 'primereact/accordion';
export default function MultipleDemo() {
return (
<div className="card">
<Accordion multiple className="max-w-md mx-auto">
<Accordion.Panel value="1">
<Accordion.Header>
What is this service about?
<Accordion.HeaderIndicator />
</Accordion.Header>
<Accordion.Content>
<p>This service helps you manage your projects more efficiently by offering real-time collaboration, task tracking, and powerful analytics. Whether you’re working solo or in a team, it’s built to scale with your needs.</p>
</Accordion.Content>
</Accordion.Panel>
<Accordion.Panel value="2">
<Accordion.Header>
Is my data secure?
<Accordion.HeaderIndicator />
</Accordion.Header>
<Accordion.Content>
<p>Yes. We use end-to-end encryption and follow industry best practices to ensure your data is protected. Your information is stored on secure servers and regularly backed up.</p>
</Accordion.Content>
</Accordion.Panel>
<Accordion.Panel value="3">
<Accordion.Header>
Can I upgrade or downgrade my plan later?
<Accordion.HeaderIndicator />
</Accordion.Header>
<Accordion.Content>
<p>Absolutely. You can change your subscription plan at any time from your account settings. Changes take effect immediately, and any billing adjustments are handled automatically.</p>
</Accordion.Content>
</Accordion.Panel>
</Accordion>
</div>
);
}
The Accordion.HeaderIndicator
component is used to display the indicator of the header. It can be customized by passing a function that returns a React element or data-p-active
attribute.
import { MinusIcon, PlusIcon } from '@primereact/icons';
import type { AccordionHeaderIndicatorInstance } from '@primereact/types/shared/accordion';
import { Accordion } from 'primereact/accordion';
export default function CustomIndicatorDemo() {
return (
<div className="card">
<Accordion className="max-w-md mx-auto" multiple>
<Accordion.Panel value="1">
<Accordion.Header>
What is this service about?
<Accordion.HeaderIndicator className="group">
<PlusIcon className="group-data-[p-active=true]:rotate-45 transition-transform ease-out" />
</Accordion.HeaderIndicator>
</Accordion.Header>
<Accordion.Content>
<p>
This service helps you manage your projects more efficiently by offering real-time collaboration, task tracking, and powerful analytics. Whether you're working solo or in a team, it's built to scale with your
needs.
</p>
</Accordion.Content>
</Accordion.Panel>
<Accordion.Panel value="2">
<Accordion.Header>
Is my data secure?
<Accordion.HeaderIndicator>{({ accordionpanel }: AccordionHeaderIndicatorInstance) => (accordionpanel?.active ? <MinusIcon /> : <PlusIcon />)}</Accordion.HeaderIndicator>
</Accordion.Header>
<Accordion.Content>
<p>Yes. We use end-to-end encryption and follow industry best practices to ensure your data is protected. Your information is stored on secure servers and regularly backed up.</p>
</Accordion.Content>
</Accordion.Panel>
<Accordion.Panel value="3">
<Accordion.Header className="justify-start gap-2">
<Accordion.HeaderIndicator />
Can I upgrade or downgrade my plan later?
</Accordion.Header>
<Accordion.Content>
<p>Absolutely. You can change your subscription plan at any time from your account settings. Changes take effect immediately, and any billing adjustments are handled automatically.</p>
</Accordion.Content>
</Accordion.Panel>
</Accordion>
</div>
);
}
Enabling disabled
property of an Accordion.Panel
prevents user interaction of the panel or enable disabled
of the Accordion
component disables all panels.
import { Accordion } from 'primereact/accordion';
export default function DisabledDemo() {
return (
<div className="card space-y-8">
<Accordion disabled className="max-w-md mx-auto">
<Accordion.Panel value="1">
<Accordion.Header>
How do I reset my password?
<Accordion.HeaderIndicator />
</Accordion.Header>
<Accordion.Content>
<p>You can reset your password by clicking the “Forgot password?” link on the login page. We’ll send a password reset link to your registered email address.</p>
</Accordion.Content>
</Accordion.Panel>
<Accordion.Panel value="2">
<Accordion.Header>
Do you offer team accounts?
<Accordion.HeaderIndicator />
</Accordion.Header>
<Accordion.Content>
<p>Yes. Our Team and Business plans are designed for collaboration. You can invite team members, assign roles, and manage permissions easily from your dashboard.</p>
</Accordion.Content>
</Accordion.Panel>
</Accordion>
<Accordion className="max-w-md mx-auto">
<Accordion.Panel value="1">
<Accordion.Header>
What happens if I exceed my usage limit?
<Accordion.HeaderIndicator />
</Accordion.Header>
<Accordion.Content>
<p>If you go over your plan limits (e.g., storage or API requests), you’ll receive a notification. You can either upgrade your plan or wait until the next billing cycle resets.</p>
</Accordion.Content>
</Accordion.Panel>
<Accordion.Panel value="2" disabled>
<Accordion.Header>
Is there a mobile app available?
<Accordion.HeaderIndicator />
</Accordion.Header>
<Accordion.Content>
<p>Yes, we offer both iOS and Android apps so you can manage your account and stay connected on the go.</p>
</Accordion.Content>
</Accordion.Panel>
</Accordion>
</div>
);
}
The optional as
property controls the default container element of a header, for example setting it to a div renders a div for the header instead of a button. The asChild
option enables the headless mode for further customization by passing callbacks and properties to implement your own header.
import { Icon } from '@primereact/core/icon';
import type { AccordionHeaderInstance } from '@primereact/types/shared/accordion';
import { Accordion } from 'primereact/accordion';
const items = [
{
label: 'What is this service about?',
value: '1',
icon: 'pi pi-question-circle text-yellow-500',
content: 'This service helps you manage your projects more efficiently by offering real-time collaboration, task tracking, and powerful analytics. Whether you’re working solo or in a team, it’s built to scale with your needs.'
},
{
label: 'Is my data secure?',
value: '2',
icon: 'pi pi-lock text-blue-500',
content: 'Yes. We use end-to-end encryption and follow industry best practices to ensure your data is protected. Your information is stored on secure servers and regularly backed up.'
},
{
label: 'Can I upgrade or downgrade my plan later?',
value: '3',
icon: 'pi pi-credit-card text-green-500',
content: 'Absolutely. You can change your subscription plan at any time from your account settings. Changes take effect immediately, and any billing adjustments are handled automatically.'
}
];
export default function TemplateDemo() {
return (
<div className="card">
<Accordion className="max-w-md mx-auto border border-surface-200 dark:border-surface-700 rounded-md divide-y divide-surface-200 dark:divide-surface-700">
{items.map((item) => (
<Accordion.Panel key={item.value} value={item.value} className="last:border-none transition-all ease-out">
<Accordion.Header className="bg-transparent py-3.5">
<span className="flex items-center gap-4">
<i className={item.icon}></i>
<span className="font-medium">{item.label}</span>
</span>
<Accordion.HeaderIndicator>{({ accordionpanel }: AccordionHeaderInstance) => <Icon className="pi pi-plus transition-transform ease-out" rotate={accordionpanel?.active ? 45 : 0} />}</Accordion.HeaderIndicator>
</Accordion.Header>
<Accordion.Content className="bg-transparent px-4 pb-3.5 leading-6 pl-13">
<p>{item.content}</p>
</Accordion.Content>
</Accordion.Panel>
))}
</Accordion>
</div>
);
}
RadioButton
component can be used to group multiple Accordion.Panel
components.
import type { useAccordionChangeEvent } from '@primereact/types/shared/accordion';
import type { RadioButtonGroupValueChangeEvent } from '@primereact/types/shared/radiobutton';
import { Accordion } from 'primereact/accordion';
import { Button } from 'primereact/button';
import { RadioButton } from 'primereact/radiobutton';
import * as React from 'react';
const items = [
{
label: 'Starter Plan',
description: 'Perfect for individuals getting started. Includes access to core components and community support.',
value: '1',
price: '$99'
},
{
label: 'Growth Plan',
description: 'Ideal for freelancers and small teams. Unlocks advanced UI components and priority email support.',
value: '2',
price: '$249'
},
{
label: 'Scale Plan',
description: 'Best for growing businesses. Includes all features, early access to new releases, and Slack support.',
value: '3',
price: '$499'
}
];
export default function UseWithRadioButton() {
const [selected, setSelected] = React.useState<string>('1');
return (
<div className="card">
<div className="max-w-md mx-auto w-full">
<RadioButton.Group className="w-full" value={selected} onValueChange={(e: RadioButtonGroupValueChangeEvent) => setSelected(e.value as string)}>
<Accordion
value={selected}
onChange={(e: useAccordionChangeEvent) => setSelected(e.value as string)}
className="w-full border border-surface-200 dark:border-surface-700 rounded-md divide-y divide-surface-200 dark:divide-surface-700"
>
{items.map((item) => (
<Accordion.Panel key={item.value} value={item.value} className="last:border-none transition-all ease-out">
<Accordion.Header onClick={() => setSelected(item.value)} className="flex items-center justify-between bg-transparent py-3.5">
<span className="flex items-center gap-4">
<RadioButton inputId={`radio-${item.value}`} name="price" value={item.value} />
<span className="font-semibold text-xl">{item.label}</span>
</span>
<span className="text-xl font-semibold">{item.price}</span>
</Accordion.Header>
<Accordion.Content className="bg-transparent px-4 pb-3.5 leading-6 pl-14">
<p>{item.description}</p>
</Accordion.Content>
</Accordion.Panel>
))}
</Accordion>
</RadioButton.Group>
<Button className="w-full mt-4" size="large">
Buy Now for {items.find((item) => item.value === selected)?.price}
</Button>
</div>
</div>
);
}
Accordion header elements is a button element and use aria-controls to define the id of the content section along with aria-expanded for the visibility state. The value to read a header element defaults to the value of the header property and can be customized by defining an aria-label or aria-labelledby via the pt property.
The content uses region role, defines an id that matches the aria-controls of the header and aria-labelledby referring to the id of the header.
Key | Function |
---|---|
tab | Moves focus to the next focusable element in the page tab sequence. |
shift + tab | Moves focus to the previous focusable element in the page tab sequence. |
enter | Toggles the visibility of the content. |
space | Toggles the visibility of the content. |
down arrow | Moves focus to the next header. If focus is on the last header, moves focus to the first header. |
up arrow | Moves focus to the previous header. If focus is on the first header, moves focus to the last header. |
home | Moves focus to the first header. |
end | Moves focus to the last header. |