Accordion

Accordion groups a collection of contents in panels.

Usage#

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>

Examples#

Basic#

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>
    );
}

Multiple#

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>
    );
}

Custom Indicator#

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&apos;re working solo or in a team, it&apos;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>
    );
}

Disabled#

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>
    );
}

Template#

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>
    );
}

With RadioButton#

RadioButton component can be used to group multiple Accordion.Panel components.

Perfect for individuals getting started. Includes access to core components and community support.

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>
    );
}

Accessibility#

Screen Reader#

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.

Header Keyboard Support#

KeyFunction
tabMoves focus to the next focusable element in the page tab sequence.
shift + tabMoves focus to the previous focusable element in the page tab sequence.
enterToggles the visibility of the content.
spaceToggles the visibility of the content.
down arrowMoves focus to the next header. If focus is on the last header, moves focus to the first header.
up arrowMoves focus to the previous header. If focus is on the first header, moves focus to the last header.
homeMoves focus to the first header.
endMoves focus to the last header.