component
A collapsible disclosure component following the W3C ARIA accordion pattern. Each item has an <h3>-wrapped trigger <button> paired with a role="region" panel. Adjacent interactive controls (action buttons, drag handles) live as siblings of the trigger inside the header row — independently focusable, never nested inside a button.
Find-in-page (Ctrl/⌘+F) still reveals text in collapsed panels: the panel carries hidden="until-found" when closed, and the browser’s beforematch event opens the matching item (Chromium; Firefox/Safari skip the auto-reveal, matching their native <details> behavior).
The type prop controls how many items can be open at once. single (default) collapses the previously open item when another opens — keeping the view focused. multiple lets any number of items be open simultaneously.
Use collapsible (default true) on single accordions to allow the open item to be collapsed back to nothing.
Pindoba is a design system providing framework-agnostic UI components for Astro, React, and Svelte.
Install individual packages via pnpm, for example:pnpm add @pindoba/astro-accordion.
Yes — every component exposes a passThrough prop for custom styles and HTML attributes on each slot.
Pindoba is a design system providing framework-agnostic UI components for Astro, React, and Svelte.
Install individual packages via pnpm, for example:pnpm add @pindoba/astro-accordion.
Yes — every component exposes a passThrough prop for custom styles and HTML attributes on each slot.
This item can be expanded and collapsed normally.
This item is not accessible when disabled.
This item is also available for interaction.
---
import Accordion from "../Accordion.astro";
import AccordionItem from "../AccordionItem.astro";
import { stack } from "@pindoba/styled-system/patterns";
---
<div
class={stack({
gap: "xl",
direction: "column",
})}
>
<!-- Single mode (default) -->
<div>
<h3>Single</h3>
<Accordion type="single" data-collapsible="true">
<AccordionItem value="item-1" title="What is Pindoba?" open>
<p>
Pindoba is a design system providing framework-agnostic UI components
for Astro, React, and Svelte.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="How do I install it?">
<p>
Install individual packages via pnpm, for example:
<code>pnpm add @pindoba/astro-accordion</code>.
</p>
</AccordionItem>
<AccordionItem value="item-3" title="Is it customizable?">
<p>
Yes — every component exposes a <code>passThrough</code> prop for custom
styles and HTML attributes on each slot.
</p>
</AccordionItem>
</Accordion>
</div>
<!-- Multiple mode -->
<div>
<h3>Multiple</h3>
<Accordion type="multiple">
<AccordionItem value="item-1" title="What is Pindoba?" open>
<p>
Pindoba is a design system providing framework-agnostic UI components
for Astro, React, and Svelte.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="How do I install it?" open>
<p>
Install individual packages via pnpm, for example:
<code>pnpm add @pindoba/astro-accordion</code>.
</p>
</AccordionItem>
<AccordionItem value="item-3" title="Is it customizable?">
<p>
Yes — every component exposes a <code>passThrough</code> prop for custom
styles and HTML attributes on each slot.
</p>
</AccordionItem>
</Accordion>
</div>
<!-- Disabled item -->
<div>
<h3>Disabled Item</h3>
<Accordion type="single">
<AccordionItem value="item-1" title="Available Section" open>
<p>This item can be expanded and collapsed normally.</p>
</AccordionItem>
<AccordionItem value="item-2" title="Disabled Section" disabled>
<p>This item is not accessible when disabled.</p>
</AccordionItem>
<AccordionItem value="item-3" title="Another Available Section">
<p>This item is also available for interaction.</p>
</AccordionItem>
</Accordion>
</div>
</div>Three sizes scale the trigger padding, content padding, and font size together. The size is set once on the root <Accordion> and inherited by every item.
Small size uses tighter padding and a smaller font — suitable for dense layouts or secondary content areas.
Inherits size="sm" from the root — no need to repeat on each item.
Medium size is the default — balanced padding and font size for most use cases.
Inherits size="md" from the root.
Large size uses generous padding and a larger font — ideal for prominent content or marketing pages.
Inherits size="lg" from the root.
This item uses the root's size="sm".
This item sets its own size="lg", which overrides the root's sm.
Back to inheriting from the root.
---
import Accordion from "../Accordion.astro";
import AccordionItem from "../AccordionItem.astro";
import { stack } from "@pindoba/styled-system/patterns";
---
<div
class={stack({
gap: "xl",
direction: "column",
})}
>
<!-- Small — size on the root cascades to items via CSS variables -->
<div>
<h3>Small</h3>
<Accordion type="single" size="sm">
<AccordionItem value="item-1" title="Compact section" open>
<p>
Small size uses tighter padding and a smaller font — suitable for
dense layouts or secondary content areas.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="Another compact section">
<p>
Inherits <code>size="sm"</code> from the root — no need to repeat on each
item.
</p>
</AccordionItem>
</Accordion>
</div>
<!-- Medium (default) -->
<div>
<h3>Medium (default)</h3>
<Accordion type="single" size="md">
<AccordionItem value="item-1" title="Standard section" open>
<p>
Medium size is the default — balanced padding and font size for most
use cases.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="Another standard section">
<p>Inherits <code>size="md"</code> from the root.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Large -->
<div>
<h3>Large</h3>
<Accordion type="single" size="lg">
<AccordionItem value="item-1" title="Spacious section" open>
<p>
Large size uses generous padding and a larger font — ideal for
prominent content or marketing pages.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="Another spacious section">
<p>Inherits <code>size="lg"</code> from the root.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Per-item override -->
<div>
<h3>Per-item override</h3>
<Accordion type="single" size="sm">
<AccordionItem value="item-1" title="Small (inherited)" open>
<p>This item uses the root's <code>size="sm"</code>.</p>
</AccordionItem>
<AccordionItem value="item-2" title="Large (override)" size="lg">
<p>
This item sets its own <code>size="lg"</code>, which overrides the
root's <code>sm</code>.
</p>
</AccordionItem>
<AccordionItem value="item-3" title="Small again (inherited)">
<p>Back to inheriting from the root.</p>
</AccordionItem>
</Accordion>
</div>
</div>For data-driven usage, pass an items array to <Accordion> and it renders one <AccordionItem> per entry. Root-level props (size, feedback, background, …) act as defaults; each entry can override via its own fields. Body content is provided per framework: named slots in Astro (<Fragment slot="<value>">), named snippets or the snippets map in Svelte (keyed by each item’s value). For rich custom trigger content, fall back to slot composition with <AccordionItem> directly.
Rendered from a named slot matching the item's value. Inherits size="md" and feedback="primary" from the root.
Same defaults as the first.
Also inherits from the root.
Uses root defaults.
Item sets size: "lg", which wins over the root's sm.
Item sets feedback: "danger", which wins over the root'sneutral.
Set per item.
Configure sign-in options.
Manage database connectivity.
Configure object storage and CDN.
---
import Accordion from "../Accordion.astro";
import { stack } from "@pindoba/styled-system/patterns";
---
<div
class={stack({
gap: "xl",
direction: "column",
})}
>
<!-- Basic items array with named slots -->
<div>
<h3>Items array with cascaded defaults</h3>
<Accordion
type="single"
size="md"
feedback="primary"
items={[
{ value: "first", title: "First", open: true },
{ value: "second", title: "Second" },
{ value: "third", title: "Third" },
]}
>
<Fragment slot="first">
<p>
Rendered from a named slot matching the item's <code>value</code>.
Inherits <code>size="md"</code> and <code>feedback="primary"</code> from
the root.
</p>
</Fragment>
<Fragment slot="second">
<p>Same defaults as the first.</p>
</Fragment>
<Fragment slot="third">
<p>Also inherits from the root.</p>
</Fragment>
</Accordion>
</div>
<!-- Per-item overrides -->
<div>
<h3>Per-item overrides</h3>
<Accordion
type="multiple"
size="sm"
feedback="neutral"
items={[
{
value: "default",
title: "Default (size=sm, feedback=neutral)",
open: true,
},
{ value: "larger", title: "Overrides size", size: "lg", open: true },
{ value: "danger", title: "Overrides feedback", feedback: "danger" },
{ value: "disabled", title: "Disabled", disabled: true },
]}
>
<Fragment slot="default">
<p>Uses root defaults.</p>
</Fragment>
<Fragment slot="larger">
<p>
Item sets <code>size: "lg"</code>, which wins over the root's <code
>sm</code
>.
</p>
</Fragment>
<Fragment slot="danger">
<p>
Item sets <code>feedback: "danger"</code>, which wins over the root's
<code>neutral</code>.
</p>
</Fragment>
<Fragment slot="disabled">
<p>Set per item.</p>
</Fragment>
</Accordion>
</div>
<!-- Subtitles -->
<div>
<h3>With subtitles</h3>
<Accordion
type="single"
size="md"
items={[
{
value: "auth",
title: "Authentication",
subtitle: "OAuth providers and session settings",
},
{
value: "db",
title: "Database",
subtitle: "Connection strings, pooling, migrations",
},
{
value: "storage",
title: "Storage",
subtitle: "File uploads and CDN",
},
]}
>
<Fragment slot="auth">
<p>Configure sign-in options.</p>
</Fragment>
<Fragment slot="db">
<p>Manage database connectivity.</p>
</Fragment>
<Fragment slot="storage">
<p>Configure object storage and CDN.</p>
</Fragment>
</Accordion>
</div>
</div>Accordion items use Panel under the hood — pass feedback and border on the root to color all items consistently. Use feedback for semantic meaning: primary for key content, success for completed flows, warning for notices, and danger for critical information.
Neutral is the default feedback color — use it for standard content without any special semantic meaning.
Each item inherits the feedback color and border from the root.
Primary feedback applies the brand color palette — use it to highlight important content or onboarding steps.
Each item inherits the feedback color and border from the root.
Success feedback conveys positive outcomes — use it for completed steps, confirmation flows, or resolved states.
Each item inherits the feedback color and border from the root.
Warning feedback draws attention to caution states — use it for deprecation notices, rate limits, or soft restrictions.
Each item inherits the feedback color and border from the root.
Danger feedback signals critical or destructive information — use it for breaking changes, error states, or irreversible actions.
Each item inherits the feedback color and border from the root.
---
import Accordion from "../Accordion.astro";
import AccordionItem from "../AccordionItem.astro";
import { stack } from "@pindoba/styled-system/patterns";
---
<div
class={stack({
gap: "xl",
direction: "column",
})}
>
<!-- Neutral -->
<div>
<h3>Neutral</h3>
<Accordion type="single" feedback="neutral">
<AccordionItem value="item-1" title="General information" open>
<p>
Neutral is the default feedback color — use it for standard content
without any special semantic meaning.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="Additional details">
<p>Each item inherits the feedback color and border from the root.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Primary -->
<div>
<h3>Primary</h3>
<Accordion type="single" feedback="primary">
<AccordionItem value="item-1" title="Getting started" open>
<p>
Primary feedback applies the brand color palette — use it to highlight
important content or onboarding steps.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="Next steps">
<p>Each item inherits the feedback color and border from the root.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Success -->
<div>
<h3>Success</h3>
<Accordion type="single" feedback="success">
<AccordionItem value="item-1" title="Completed tasks" open>
<p>
Success feedback conveys positive outcomes — use it for completed
steps, confirmation flows, or resolved states.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="What's next">
<p>Each item inherits the feedback color and border from the root.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Warning -->
<div>
<h3>Warning</h3>
<Accordion type="single" feedback="warning">
<AccordionItem value="item-1" title="Deprecation notice" open>
<p>
Warning feedback draws attention to caution states — use it for
deprecation notices, rate limits, or soft restrictions.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="Migration guide">
<p>Each item inherits the feedback color and border from the root.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Danger -->
<div>
<h3>Danger</h3>
<Accordion type="single" feedback="danger">
<AccordionItem value="item-1" title="Breaking changes" open>
<p>
Danger feedback signals critical or destructive information — use it
for breaking changes, error states, or irreversible actions.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="How to resolve">
<p>Each item inherits the feedback color and border from the root.</p>
</AccordionItem>
</Accordion>
</div>
</div>emphasis follows panel’s three-tier model. primary fills each item with the feedback accent surface and contrast text. secondary (default) uses the feedback-tinted soft surface — the standard accordion look. tertiary keeps the surface neutral but tints the trigger text and border with the feedback color, useful when a tinted background would compete with the surrounding page.
Set emphasis per <AccordionItem> for slot-composed accordions (each child carries its own panel surface). When you use the items array on <Accordion>, the root-level emphasis acts as a default for every item — same shape as background, border, and padding.
Primary emphasis fills each item with the feedback's accent surface and uses contrast text. Use it for the most prominent accordion sections.
The trigger and indicator read against the bold surface.
Secondary emphasis paints each item with the feedback's soft surface. This is the default — most accordions use it.
Trigger text picks up the feedback's accent color.
Tertiary emphasis keeps the surface neutral but tints the text and border with the feedback color. Useful when a tinted background would compete with surrounding content.
The trigger and content read against neutral surface.
---
import Accordion from "../Accordion.astro";
import AccordionItem from "../AccordionItem.astro";
import { stack } from "@pindoba/styled-system/patterns";
---
<div class={stack({ gap: "xl", direction: "column" })}>
<!-- Primary — filled feedback accent surface -->
<div>
<h3>Primary</h3>
<Accordion type="single" feedback="primary">
<AccordionItem
value="item-1"
title="Filled accent surface"
emphasis="primary"
open
>
<p>
Primary emphasis fills each item with the feedback's accent surface
and uses contrast text. Use it for the most prominent accordion
sections.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="More detail" emphasis="primary">
<p>The trigger and indicator read against the bold surface.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Secondary (default) — feedback-tinted soft surface -->
<div>
<h3>Secondary (default)</h3>
<Accordion type="single" feedback="primary">
<AccordionItem value="item-1" title="Feedback-tinted soft surface" open>
<p>
Secondary emphasis paints each item with the feedback's soft surface.
This is the default — most accordions use it.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="More detail">
<p>Trigger text picks up the feedback's accent color.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Tertiary — neutral surface, feedback-tinted text -->
<div>
<h3>Tertiary</h3>
<Accordion type="single" feedback="primary">
<AccordionItem
value="item-1"
title="Neutral surface, feedback text"
emphasis="tertiary"
open
>
<p>
Tertiary emphasis keeps the surface neutral but tints the text and
border with the feedback color. Useful when a tinted background would
compete with surrounding content.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="More detail" emphasis="tertiary">
<p>The trigger and content read against neutral surface.</p>
</AccordionItem>
</Accordion>
</div>
</div>Accordion items use Banner internally for their trigger area. This means you can add a subtitle, inline icons via headingLeading / headingTrailing, and a trailing element at the far right of the trigger row — all without replacing the whole trigger. These slots are decorative — they render inside the trigger button, so don’t put interactive controls (like <button> or links) here. For interactive header controls, see Header Actions below.
Add a subtitle to provide secondary context below the title without losing the clickable trigger area.
Configure your database connection and migration settings here.
Set up file storage providers and CDN delivery options.
Use the heading-trailing slot to place a badge, count, or status indicator inline with the title text.
Active pull requests waiting for review.
Recent deployment activity and logs.
Use the heading-leading slot to prepend a Stamp icon directly beside the title text.
Notification preferences and delivery settings.
Two-factor authentication and session management.
General application preferences and defaults.
Use the trailing slot to place content at the far right of the trigger row — outside the title/subtitle, before the expand indicator.
Current build cache status and invalidation controls.
---
import Accordion from "../Accordion.astro";
import AccordionItem from "../AccordionItem.astro";
import Stamp from "@pindoba/astro-stamp";
import {
Bell,
Database,
HardDrive,
KeyRound,
Settings,
Shield,
User,
} from "@lucide/astro";
import { stack } from "@pindoba/styled-system/patterns";
import { css } from "@pindoba/styled-system/css";
const badge = css({
display: "inline-flex",
alignItems: "center",
px: "xs",
py: "3xs",
borderRadius: "full",
fontSize: "xs",
fontWeight: "semibold",
background: "colorPalette.surface.valley",
color: "colorPalette.text",
});
---
<div
class={stack({
gap: "xl",
direction: "column",
})}
>
<!-- Subtitle -->
<div>
<h3>Subtitle</h3>
<Accordion type="single" collapsible>
<AccordionItem
value="item-1"
title="Authentication"
subtitle="Configure OAuth providers and session settings"
>
<Stamp
slot="leading"
feedback="neutral"
emphasis="secondary"
shape="square"
>
<KeyRound />
</Stamp>
<p>
Add a <code>subtitle</code> to provide secondary context below the title
without losing the clickable trigger area.
</p>
</AccordionItem>
<AccordionItem
value="item-2"
title="Database"
subtitle="Connection strings, pooling, and migrations"
>
<Stamp
slot="leading"
feedback="neutral"
emphasis="secondary"
shape="square"
>
<Database />
</Stamp>
<p>Configure your database connection and migration settings here.</p>
</AccordionItem>
<AccordionItem
value="item-3"
title="Storage"
subtitle="File uploads and CDN configuration"
>
<Stamp
slot="leading"
feedback="neutral"
emphasis="secondary"
shape="square"
>
<HardDrive />
</Stamp>
<p>Set up file storage providers and CDN delivery options.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Heading trailing — count or status badge -->
<div>
<h3>Heading Trailing</h3>
<Accordion type="multiple">
<AccordionItem value="item-1" title="Open Issues">
<span slot="heading-trailing" class={badge}>12</span>
<p>
Use the <code>heading-trailing</code> slot to place a badge, count, or status
indicator inline with the title text.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="Pull Requests">
<span slot="heading-trailing" class={badge}>3</span>
<p>Active pull requests waiting for review.</p>
</AccordionItem>
<AccordionItem value="item-3" title="Deployments">
<span slot="heading-trailing" class={badge}>1</span>
<p>Recent deployment activity and logs.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Leading icon -->
<div>
<h3>Leading Icon</h3>
<Accordion type="single" collapsible>
<AccordionItem value="item-1" title="Profile">
<Stamp
slot="heading-leading"
feedback="primary"
emphasis="secondary"
shape="circle"
size="xs"
>
<User />
</Stamp>
<p>
Use the <code>heading-leading</code> slot to prepend a Stamp icon directly
beside the title text.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="Notifications">
<Stamp
slot="heading-leading"
feedback="warning"
emphasis="secondary"
shape="circle"
size="xs"
>
<Bell />
</Stamp>
<p>Notification preferences and delivery settings.</p>
</AccordionItem>
<AccordionItem value="item-3" title="Security">
<Stamp
slot="heading-leading"
feedback="success"
emphasis="secondary"
shape="circle"
size="xs"
>
<Shield />
</Stamp>
<p>Two-factor authentication and session management.</p>
</AccordionItem>
<AccordionItem value="item-4" title="Preferences">
<Stamp
slot="heading-leading"
feedback="neutral"
emphasis="secondary"
shape="circle"
size="xs"
>
<Settings />
</Stamp>
<p>General application preferences and defaults.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Trailing row action -->
<div>
<h3>Trailing Action</h3>
<Accordion type="single" collapsible>
<AccordionItem value="item-1" title="Environment Variables">
<span
slot="trailing"
class={css({
fontSize: "xs",
color: "neutral.text.muted",
fontWeight: "normal",
flexShrink: 0,
})}
>
12 variables
</span>
<p>
Use the <code>trailing</code> slot to place content at the far right of
the trigger row — outside the title/subtitle, before the expand indicator.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="Build Cache">
<span
slot="trailing"
class={css({
fontSize: "xs",
color: "success.text",
fontWeight: "semibold",
flexShrink: 0,
})}
>
Active
</span>
<p>Current build cache status and invalidation controls.</p>
</AccordionItem>
</Accordion>
</div>
</div>When an item needs interactive controls in its header — a delete button, an overflow menu, a drag handle — use the adjacent slots: actionsLeading (left of the trigger) and actionsTrailing (right of the trigger). They render as siblings of the trigger inside the header row, so activating them doesn’t toggle the accordion and they’re independently focusable.
There are two tiers of header slots — pick the right one for the job:
leading, trailing, headingLeading, headingTrailing, subheadingLeading, subheadingTrailing): rendered inside the trigger button. Icons, badges, counts. No interactive children.actionsLeading, actionsTrailing): rendered next to the trigger. Buttons, menu triggers, drag handles.Use the actions-trailing named slot for interactive controls that sit next to the trigger without toggling it.
Click the icon buttons — they don't toggle the accordion.
An ellipsis menu placed alongside the trigger.
Use the actions-leading named slot for a drag handle (or any leading control). Activating it doesn't toggle the panel.
Layer settings for the background plate.
Layer settings for the foreground content.
Layer settings for the top overlay.
---
import Accordion from "../Accordion.astro";
import AccordionItem from "../AccordionItem.astro";
import Button from "@pindoba/astro-button";
import { Ellipsis, GripVertical, Pencil, Trash2 } from "@lucide/astro";
import { stack } from "@pindoba/styled-system/patterns";
import { css } from "@pindoba/styled-system/css";
const handle = css({
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
p: "2xs",
color: "neutral.text.muted",
cursor: "grab",
borderRadius: "xs",
_hover: { background: "neutral.surface.hill", color: "neutral.text" },
_focusVisible: { pindobaOutline: true },
_active: { cursor: "grabbing" },
});
---
<div class={stack({ gap: "xl", direction: "column" })}>
<!-- Trailing actions -->
<div>
<h3>Trailing actions</h3>
<p>
Use the <code>actions-trailing</code> named slot for interactive controls that
sit next to the trigger without toggling it.
</p>
<Accordion type="single" collapsible>
<AccordionItem
value="profile"
title="Profile"
subtitle="Name, avatar, and bio"
>
<Fragment slot="actions-trailing">
<Button emphasis="ghost" size="sm" shape="square" aria-label="Edit">
<Pencil />
</Button>
<Button
emphasis="ghost"
size="sm"
shape="square"
feedback="danger"
aria-label="Delete"
>
<Trash2 />
</Button>
</Fragment>
<p>Click the icon buttons — they don't toggle the accordion.</p>
</AccordionItem>
<AccordionItem
value="billing"
title="Billing"
subtitle="Plan and invoices"
>
<Button
slot="actions-trailing"
emphasis="ghost"
size="sm"
shape="square"
aria-label="More"
>
<Ellipsis />
</Button>
<p>An ellipsis menu placed alongside the trigger.</p>
</AccordionItem>
</Accordion>
</div>
<!-- Leading drag handle -->
<div>
<h3>Leading drag handle</h3>
<p>
Use the <code>actions-leading</code> named slot for a drag handle (or any leading
control). Activating it doesn't toggle the panel.
</p>
<Accordion type="multiple">
<AccordionItem value="layer-1" title="Background">
<button
slot="actions-leading"
type="button"
class={handle}
aria-label="Reorder Background"
>
<GripVertical />
</button>
<p>Layer settings for the background plate.</p>
</AccordionItem>
<AccordionItem value="layer-2" title="Foreground">
<button
slot="actions-leading"
type="button"
class={handle}
aria-label="Reorder Foreground"
>
<GripVertical />
</button>
<Button
slot="actions-trailing"
emphasis="ghost"
size="sm"
shape="square"
aria-label="Edit Foreground"
>
<Pencil />
</Button>
<p>Layer settings for the foreground content.</p>
</AccordionItem>
<AccordionItem value="layer-3" title="Overlay">
<button
slot="actions-leading"
type="button"
class={handle}
aria-label="Reorder Overlay"
>
<GripVertical />
</button>
<p>Layer settings for the top overlay.</p>
</AccordionItem>
</Accordion>
</div>
</div>The passThrough prop on AccordionItem reaches into any slot — item, header, heading, trigger, indicator, actionsLeading, actionsTrailing, content, contentInner. Use style for Panda CSS overrides and props for extra HTML attributes. On the root Accordion, passThrough.root applies to the wrapper <div>.
Use passThrough.trigger.style on an item to restyle its trigger — here applying a monospace font for a file-tree appearance.
The style is applied via Panda CSS css.raw(), giving you full access to design tokens and responsive utilities.
Use passThrough.content.style on an item to customize its content area — here adding a bold top border using the current feedback color palette.
Each item's content slot gets the same custom styles.
Use passThrough.root.props on the accordion to forward HTML attributes to the root element — here addingrole="region" and an aria-label for screen reader context.
passThrough is the escape hatch for any customization not covered by component props. It keeps the public API clean while remaining fully flexible.
---
import Accordion from "../Accordion.astro";
import AccordionItem from "../AccordionItem.astro";
import { stack } from "@pindoba/styled-system/patterns";
import { css } from "@pindoba/styled-system/css";
---
<div
class={stack({
gap: "xl",
direction: "column",
})}
>
<!-- Custom trigger style -->
<div>
<h3>Custom Trigger Style</h3>
<Accordion type="single">
<AccordionItem
value="item-1"
title="src/index.ts"
open
passThrough={{
trigger: {
style: css.raw({
fontFamily: "mono",
fontSize: "sm",
letterSpacing: "0.04em",
}),
},
}}
>
<p>
Use <code>passThrough.trigger.style</code> on an item to restyle its trigger
— here applying a monospace font for a file-tree appearance.
</p>
</AccordionItem>
<AccordionItem
value="item-2"
title="src/components/Button.astro"
passThrough={{
trigger: {
style: css.raw({
fontFamily: "mono",
fontSize: "sm",
letterSpacing: "0.04em",
}),
},
}}
>
<p>
The style is applied via Panda CSS <code>css.raw()</code>, giving you
full access to design tokens and responsive utilities.
</p>
</AccordionItem>
</Accordion>
</div>
<!-- Custom content style -->
<div>
<h3>Custom Content Style</h3>
<Accordion type="single" feedback="primary">
<AccordionItem
value="item-1"
title="Separated content area"
open
passThrough={{
content: {
style: css.raw({
borderTop: "2px solid",
borderColor: "colorPalette.border.bold",
}),
},
}}
>
<p>
Use <code>passThrough.content.style</code> on an item to customize its content
area — here adding a bold top border using the current feedback color palette.
</p>
</AccordionItem>
<AccordionItem
value="item-2"
title="Another section"
passThrough={{
content: {
style: css.raw({
borderTop: "2px solid",
borderColor: "colorPalette.border.bold",
}),
},
}}
>
<p>Each item's content slot gets the same custom styles.</p>
</AccordionItem>
</Accordion>
</div>
<!-- ARIA attributes via passThrough props -->
<div>
<h3>ARIA Attributes</h3>
<Accordion
type="single"
passThrough={{
root: {
props: {
role: "region",
"aria-label": "Frequently asked questions",
},
},
}}
>
<AccordionItem value="item-1" title="What does this do?" open>
<p>
Use <code>passThrough.root.props</code> on the accordion to forward HTML
attributes to the root element — here adding
<code>role="region"</code> and an <code>aria-label</code> for screen reader
context.
</p>
</AccordionItem>
<AccordionItem value="item-2" title="Why use passThrough?">
<p>
<code>passThrough</code> is the escape hatch for any customization not covered
by component props. It keeps the public API clean while remaining fully
flexible.
</p>
</AccordionItem>
</Accordion>
</div>
</div>Surface level for each item's Panel background. Inherited by all items unless overridden per-item.
Box-shadow ring border applied to each item. Uses box-shadow so it is layout-neutral.
trueIn `single` mode, allow the open item to be collapsed back to nothing. Has no effect in `multiple` mode.
Uncontrolled initial list of expanded item values.
falseDisable the entire accordion and all its items.
Visual emphasis applied to each item's Panel. `primary` is a solid feedback accent surface with contrast text; `secondary` is a feedback-tinted soft surface (default); `tertiary` is a neutral surface with bold feedback-tinted text. Inherited by all items unless overridden per-item.
Semantic feedback color applied to each item's Panel background. Inherited by all items unless overridden per-item.
When provided, `<Accordion>` renders one `<AccordionItem>` per entry, applying root-level style props as defaults and letting each entry override them. Mutually exclusive with slot children (items wins, slot is ignored with a console warning in dev).
Callback fired whenever the expanded set changes.
Internal padding for each item's Panel. Inherited by all items unless overridden per-item.
Per-slot style and attribute override bag. Applies to all items.
Border radius for each item's Panel. Inherited by all items unless overridden per-item.
Border radius for the bottom corners of each item's Panel.
Border radius for the left corners of each item's Panel.
Border radius for the right corners of each item's Panel.
Border radius for the top corners of each item's Panel.
"md"Controls trigger padding, content padding, and font size for all items.
"single"Expansion behavior. `single` allows one item open at a time and collapses siblings; `multiple` allows any number of items to be open simultaneously.
Controlled list of expanded item values. Bind this prop to track or set expansion state externally.
falseDisable this individual item, preventing interaction.
falseWhether the item is open. Drives `aria-expanded`, `data-state`, and the collapsed-panel `hidden="until-found"` (which keeps the body findable by the browser's find-in-page). In Svelte this is controlled via the root accordion's `value` prop.
Per-slot style and attribute override bag for this item. Takes precedence over the root accordion's `passThrough`.
Unique identifier for this item within the accordion. Used to track expansion state.