The Accordion component provides shadcn-inspired disclosure primitives built on native HTML elements. It is ideal for FAQs, compact settings panels, and any UI where you want to reveal details progressively without custom JavaScript.
Import
use PUI
# or
import PUI.Accordion
Basic Usage
Use accordion/1 as the wrapper and compose items with accordion_item/1, accordion_trigger/1, and accordion_content/1.
<.accordion class="max-w-xl">
<.accordion_item name="faq" open>
<.accordion_trigger>Is it accessible?</.accordion_trigger>
<.accordion_content>
Yes. It uses native details and summary elements.
</.accordion_content>
</.accordion_item>
<.accordion_item name="faq">
<.accordion_trigger>Can I style it?</.accordion_trigger>
<.accordion_content>
Yes. Every part takes a `class` that replaces its default styling.
</.accordion_content>
</.accordion_item>
</.accordion>
Single Open Accordion
How do I reset my password?
Can I change my plan later?
What payment methods are supported?
<.accordion class="max-w-2xl">
<.accordion_item name="accordion-single" open>
<.accordion_trigger>How do I reset my password?</.accordion_trigger>
<.accordion_content>
Use the password reset flow from the sign-in page and follow the
emailed link to create a new password.
</.accordion_content>
</.accordion_item>
<.accordion_item name="accordion-single">
<.accordion_trigger>Can I change my plan later?</.accordion_trigger>
<.accordion_content>
Yes. You can upgrade or downgrade your plan from billing settings at
any time.
</.accordion_content>
</.accordion_item>
<.accordion_item name="accordion-single">
<.accordion_trigger>What payment methods are supported?</.accordion_trigger>
<.accordion_content>
We support major credit cards, invoice billing for larger teams, and
regional payment methods where available.
</.accordion_content>
</.accordion_item>
</.accordion>
Single Open Behavior
Set the same name on sibling accordion_item/1 entries when you want the browser to keep only one panel open at a time.
<.accordion>
<.accordion_item name="settings" open>
<.accordion_trigger>Account</.accordion_trigger>
<.accordion_content>Account settings…</.accordion_content>
</.accordion_item>
<.accordion_item name="settings">
<.accordion_trigger>Billing</.accordion_trigger>
<.accordion_content>Billing settings…</.accordion_content>
</.accordion_item>
</.accordion>
Multiple Open Items
Leave name unset to allow multiple sections to remain expanded at once.
<.accordion class="rounded-xl border border-border px-4">
<.accordion_item open class="last:border-b-0">
<.accordion_trigger>Notifications</.accordion_trigger>
<.accordion_content>Notification preferences…</.accordion_content>
</.accordion_item>
<.accordion_item class="last:border-b-0">
<.accordion_trigger>Privacy</.accordion_trigger>
<.accordion_content>Privacy controls…</.accordion_content>
</.accordion_item>
</.accordion>
Multiple Open Accordion
Notification Settings
Privacy & Security
Billing & Subscription
<.accordion class="max-w-2xl rounded-xl border border-border px-4">
<.accordion_item open class="last:border-b-0">
<.accordion_trigger>Notification Settings</.accordion_trigger>
<.accordion_content>
Manage which updates arrive by email, in-app inbox, or mobile push.
</.accordion_content>
</.accordion_item>
<.accordion_item class="last:border-b-0">
<.accordion_trigger>Privacy & Security</.accordion_trigger>
<.accordion_content>
Configure session policies, 2FA requirements, and export controls.
</.accordion_content>
</.accordion_item>
<.accordion_item class="last:border-b-0">
<.accordion_trigger>Billing & Subscription</.accordion_trigger>
<.accordion_content>
Review invoices, compare plans, and manage workspace billing owners.
</.accordion_content>
</.accordion_item>
</.accordion>
Host-owned presentation
The accordion is built on native <details>/<summary>, so it has no
hook-managed behavior and therefore no primitive module. Pass a class to each
part to take over the presentation while keeping the semantic structure:
<.accordion class="space-y-3">
<.accordion_item class="rounded-2xl border" open>
<.accordion_trigger class="flex w-full items-center justify-between px-4 py-3">
Custom trigger
</.accordion_trigger>
<.accordion_content class="px-4 pb-4 text-sm">
Fully custom content styling.
</.accordion_content>
</.accordion_item>
</.accordion>
Headless Accordion Demo
Bring your own layout
<.accordion class="max-w-2xl space-y-3">
<.accordion_item
class="overflow-hidden rounded-2xl border border-border bg-background shadow-sm"
open
>
<.accordion_trigger class="flex w-full items-center justify-between gap-4 px-5 py-4 text-left text-sm font-semibold text-foreground">
Bring your own layout <.icon name="hero-sparkles" class="size-4 text-primary" />
</.accordion_trigger>
<.accordion_content class="border-t border-border px-5 py-4 text-sm leading-6 text-muted-foreground">
This example drops the default shadcn-like treatment but keeps the
composable building blocks for your own design system.
</.accordion_content>
</.accordion_item>
</.accordion>
Notes on Styling
The default styles follow the same shadcn-inspired theme tokens used by the rest of PUI, including border-border, text-muted-foreground, and focus ring utilities. That keeps the accordion aligned with the active light or dark theme automatically.
Because the component is built on <details> and <summary>, it works well for:
- FAQ sections
- Settings categories
- Compact side panels
- Disclosure-heavy mobile layouts
API Reference
accordion/1 Attributes
| Name | Type | Default | Description |
|---|---|---|---|
class |
string |
"" |
Additional wrapper classes |
accordion_item/1 Attributes
| Name | Type | Default | Description |
|---|---|---|---|
name |
string |
nil |
Shared group name for single-open behavior |
open |
boolean |
false |
Whether the item starts expanded |
class |
string |
"" |
Additional item classes |
accordion_trigger/1 Attributes
| Name | Type | Default | Description |
|---|---|---|---|
icon |
boolean |
true |
Show the chevron icon |
class |
string |
"" |
Additional trigger classes |
accordion_content/1 Attributes
| Name | Type | Default | Description |
|---|---|---|---|
class |
string |
"" |
Additional content classes |