Accordion
This library is a work-in-progress. We are releasing it early to gather feedback, but it is not ready for production.
An accordion is a vertically stacked set of interactive headings that each reveal a section of content. Accordions are ideal for presenting FAQs, feature lists, and other content that benefits from progressive disclosure.
Examples
Live Preview
Basic Accordion (Default)
By default, the Accordion provides a chevron which points down when closed, then rotates 180° to point up when open. See below for how to opt out or use different indicators.
Default chevron indicator with smooth rotation
Click to see the 180° rotation animation
Classic accordion indicator style
X Indicator
Plus rotated 180° (upside down) when closed, rotates to 45° forming an X when open.
Plus transforms into X when opened
Smooth transition from plus to X
Modern accordion indicator style
Plus/Minus Indicator
Plus transitions to minus when open with smooth animation.
Plus changes to minus when opened
Classic expand/collapse indicator
Clear visual indication of state
No Indicator
Accordion items without any visual indicator.
Clean header without indicator icon
Minimal design focused on content
Simple accordion without visual clutter
Bordered
This accordion has borders on the headers
Another bordered item
Third bordered item
With Background
This accordion has background color on headers
Another item with background
Third item with background
One Item Open
This item starts closed
This item starts open
This item also starts closed
Disabled State
This item can be toggled
This item cannot be toggled
This item can also be toggled
Rich Content
- Accessible by default with ARIA attributes
- Keyboard navigation support
- Customizable heading levels
- Multiple styling options
<VueAccordionItem use-chevron> <VueAccordionHeader>Title</VueAccordionHeader> <VueAccordionContent>Content</VueAccordionContent> </VueAccordionItem>
Accordions are great for:
- FAQ sections
- Feature lists
- Documentation
- Progressive disclosure
CSS Parts Customization
Customize accordion appearance using CSS Shadow Parts without breaking encapsulation.
This variant uses a minimal border-left design with subtle styling.
Clean and simple styling focused on content hierarchy.
View Vue Code
<template>
<section>
<div class="mbe4">
<h2>Basic Accordion (Default)</h2>
<p
class="mbe2"
style="color: var(--ag-text-secondary); font-size: 0.875rem;"
>
By default, the Accordion provides a chevron which points down when closed, then rotates 180° to point up when open. See below for how to opt out or use different indicators.
</p>
</div>
<div class="stacked mbe4">
<VueAccordion>
<VueAccordionItem use-chevron>
<VueAccordionHeader>Chevron Section 1</VueAccordionHeader>
<VueAccordionContent>
<p>Default chevron indicator with smooth rotation</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem use-chevron>
<VueAccordionHeader>Chevron Section 2</VueAccordionHeader>
<VueAccordionContent>
<p>Click to see the 180° rotation animation</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem use-chevron>
<VueAccordionHeader>Chevron Section 3</VueAccordionHeader>
<VueAccordionContent>
<p>Classic accordion indicator style</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
</div>
<div class="mbe4">
<h2>X Indicator</h2>
<p
class="mbe2"
style="color: var(--ag-text-secondary); font-size: 0.875rem;"
>
Plus rotated 180° (upside down) when closed, rotates to 45° forming an X when open.
</p>
</div>
<div class="stacked mbe4">
<VueAccordion>
<VueAccordionItem use-x>
<VueAccordionHeader>X Indicator Section 1</VueAccordionHeader>
<VueAccordionContent>
<p>Plus transforms into X when opened</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem use-x>
<VueAccordionHeader>X Indicator Section 2</VueAccordionHeader>
<VueAccordionContent>
<p>Smooth transition from plus to X</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem use-x>
<VueAccordionHeader>X Indicator Section 3</VueAccordionHeader>
<VueAccordionContent>
<p>Modern accordion indicator style</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
</div>
<div class="mbe4">
<h2>Plus/Minus Indicator</h2>
<p
class="mbe2"
style="color: var(--ag-text-secondary); font-size: 0.875rem;"
>
Plus transitions to minus when open with smooth animation.
</p>
</div>
<div class="stacked mbe4">
<VueAccordion>
<VueAccordionItem use-minus>
<VueAccordionHeader>Plus/Minus Section 1</VueAccordionHeader>
<VueAccordionContent>
<p>Plus changes to minus when opened</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem use-minus>
<VueAccordionHeader>Plus/Minus Section 2</VueAccordionHeader>
<VueAccordionContent>
<p>Classic expand/collapse indicator</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem use-minus>
<VueAccordionHeader>Plus/Minus Section 3</VueAccordionHeader>
<VueAccordionContent>
<p>Clear visual indication of state</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
</div>
<div class="mbe4">
<h2>No Indicator</h2>
<p
class="mbe2"
style="color: var(--ag-text-secondary); font-size: 0.875rem;"
>
Accordion items without any visual indicator.
</p>
</div>
<div class="stacked mbe4">
<VueAccordion>
<VueAccordionItem no-indicator>
<VueAccordionHeader>No Indicator Section 1</VueAccordionHeader>
<VueAccordionContent>
<p>Clean header without indicator icon</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem no-indicator>
<VueAccordionHeader>No Indicator Section 2</VueAccordionHeader>
<VueAccordionContent>
<p>Minimal design focused on content</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem no-indicator>
<VueAccordionHeader>No Indicator Section 3</VueAccordionHeader>
<VueAccordionContent>
<p>Simple accordion without visual clutter</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
</div>
<div class="mbe4">
<h2>Bordered</h2>
</div>
<div class="stacked mbe4">
<VueAccordion>
<VueAccordionItem
bordered
use-chevron
>
<VueAccordionHeader>Bordered Item 1</VueAccordionHeader>
<VueAccordionContent>
<p>This accordion has borders on the headers</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem
bordered
use-chevron
>
<VueAccordionHeader>Bordered Item 2</VueAccordionHeader>
<VueAccordionContent>
<p>Another bordered item</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem
bordered
use-chevron
>
<VueAccordionHeader>Bordered Item 3</VueAccordionHeader>
<VueAccordionContent>
<p>Third bordered item</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
</div>
<div class="mbe4">
<h2>With Background</h2>
</div>
<div class="stacked mbe4">
<VueAccordion>
<VueAccordionItem
background
use-chevron
>
<VueAccordionHeader>Background Item 1</VueAccordionHeader>
<VueAccordionContent>
<p>This accordion has background color on headers</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem
background
use-chevron
>
<VueAccordionHeader>Background Item 2</VueAccordionHeader>
<VueAccordionContent>
<p>Another item with background</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem
background
use-chevron
>
<VueAccordionHeader>Background Item 3</VueAccordionHeader>
<VueAccordionContent>
<p>Third item with background</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
</div>
<div class="mbe4">
<h2>One Item Open</h2>
</div>
<div class="stacked mbe4">
<VueAccordion>
<VueAccordionItem use-chevron>
<VueAccordionHeader>Closed Item</VueAccordionHeader>
<VueAccordionContent>
<p>This item starts closed</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem
use-chevron
open
>
<VueAccordionHeader>Open Item</VueAccordionHeader>
<VueAccordionContent>
<p>This item starts open</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem use-chevron>
<VueAccordionHeader>Another Closed Item</VueAccordionHeader>
<VueAccordionContent>
<p>This item also starts closed</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
</div>
<div class="mbe4">
<h2>Disabled State</h2>
</div>
<div class="stacked mbe4">
<VueAccordion>
<VueAccordionItem use-chevron>
<VueAccordionHeader>Enabled Item</VueAccordionHeader>
<VueAccordionContent>
<p>This item can be toggled</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem
use-chevron
disabled
>
<VueAccordionHeader>Disabled Item</VueAccordionHeader>
<VueAccordionContent>
<p>This item cannot be toggled</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem use-chevron>
<VueAccordionHeader>Another Enabled Item</VueAccordionHeader>
<VueAccordionContent>
<p>This item can also be toggled</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
</div>
<div class="mbe4">
<h2>Rich Content</h2>
</div>
<div class="stacked mbe4">
<VueAccordion>
<VueAccordionItem
use-chevron
bordered
>
<VueAccordionHeader>
<div class="flex-inline items-center">
<Info
color="var(--ag-primary)"
:size="18"
class="mie2"
/>
Features
</div>
</VueAccordionHeader>
<VueAccordionContent>
<ul>
<li>Accessible by default with ARIA attributes</li>
<li>Keyboard navigation support</li>
<li>Customizable heading levels</li>
<li>Multiple styling options</li>
</ul>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem
use-chevron
bordered
>
<VueAccordionHeader>
<div class="flex-inline items-center">
<Code
color="var(--ag-secondary)"
:size="18"
class="mie2"
/>
Code Example
</div>
</VueAccordionHeader>
<VueAccordionContent>
<pre style="background: var(--ag-background-secondary); padding: 1rem; border-radius: 4px; overflow-x: auto;">
<VueAccordionItem use-chevron>
<VueAccordionHeader>Title</VueAccordionHeader>
<VueAccordionContent>Content</VueAccordionContent>
</VueAccordionItem></pre>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem
use-chevron
bordered
>
<VueAccordionHeader>
<div class="flex-inline items-center">
<HelpCircle
color="var(--ag-success)"
:size="18"
class="mie2"
/>
More Information
</div>
</VueAccordionHeader>
<VueAccordionContent>
<p>Accordions are great for:</p>
<ul>
<li>FAQ sections</li>
<li>Feature lists</li>
<li>Documentation</li>
<li>Progressive disclosure</li>
</ul>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
</div>
<div class="mbe4">
<h2>CSS Parts Customization</h2>
<p
class="mbe2"
style="color: var(--ag-text-secondary); font-size: 0.875rem;"
>
Customize accordion appearance using CSS Shadow Parts without breaking encapsulation.
</p>
</div>
<div class="stacked mbe4">
<VueAccordion>
<VueAccordionItem
class="custom-minimal-accordion"
use-chevron
>
<VueAccordionHeader>Minimal Border Style</VueAccordionHeader>
<VueAccordionContent>
<p>This variant uses a minimal border-left design with subtle styling.</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem
class="custom-minimal-accordion"
use-chevron
>
<VueAccordionHeader>Another Minimal Item</VueAccordionHeader>
<VueAccordionContent>
<p>Clean and simple styling focused on content hierarchy.</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
</div>
</section>
</template>
<script>
import VueAccordion, {
VueAccordionItem,
VueAccordionHeader,
VueAccordionContent,
} from "agnosticui-core/accordion/vue";
import { Info, Code, HelpCircle } from "lucide-vue-next";
export default {
name: "AccordionExamples",
components: {
VueAccordion,
VueAccordionItem,
VueAccordionHeader,
VueAccordionContent,
Info,
Code,
HelpCircle,
},
};
</script>
<style scoped>
/* CSS Parts customization examples */
.custom-minimal-accordion::part(ag-accordion-header-wrapper) {
border-left: 4px solid var(--ag-primary);
padding-left: 12px;
}
.custom-minimal-accordion::part(ag-accordion-header) {
font-weight: 500;
color: var(--ag-text-primary);
}
.custom-minimal-accordion::part(ag-accordion-content) {
padding-left: 16px;
border-left: 2px solid #e5e7eb;
margin-left: 2px;
}
.custom-minimal-accordion::part(ag-accordion-indicator) {
color: var(--ag-primary);
}
</style>
Live Preview
View Lit / Web Component Code
import { LitElement, html } from 'lit';
import 'agnosticui-core/accordion';
export class AccordionLitExamples extends LitElement {
// Render in light DOM to access global utility classes
createRenderRoot() {
return this;
}
render() {
return html`
<section>
<div class="mbe4">
<h2>Basic Accordion (Default)</h2>
<p class="mbe2" style="color: var(--ag-text-secondary); font-size: 0.875rem;">
By default, the Accordion provides a chevron which points down when
closed, then rotates 180° to point up when open. See below for how to
opt out or use different indicators.
</p>
</div>
<div class="stacked mbe4">
<ag-accordion>
<ag-accordion-item use-chevron>
<span slot="header">Chevron Section 1</span>
<div slot="content">
<p>Default chevron indicator with smooth rotation</p>
</div>
</ag-accordion-item>
<ag-accordion-item use-chevron>
<span slot="header">Chevron Section 2</span>
<div slot="content">
<p>Click to see the 180° rotation animation</p>
</div>
</ag-accordion-item>
<ag-accordion-item use-chevron>
<span slot="header">Chevron Section 3</span>
<div slot="content">
<p>Classic accordion indicator style</p>
</div>
</ag-accordion-item>
</ag-accordion>
</div>
<div class="mbe4">
<h2>X Indicator</h2>
<p class="mbe2" style="color: var(--ag-text-secondary); font-size: 0.875rem;">
Plus rotated 180° (upside down) when closed, rotates to 45° forming
an X when open.
</p>
</div>
<div class="stacked mbe4">
<ag-accordion>
<ag-accordion-item use-x>
<span slot="header">X Indicator Section 1</span>
<div slot="content">
<p>Plus transforms into X when opened</p>
</div>
</ag-accordion-item>
<ag-accordion-item use-x>
<span slot="header">X Indicator Section 2</span>
<div slot="content">
<p>Smooth transition from plus to X</p>
</div>
</ag-accordion-item>
<ag-accordion-item use-x>
<span slot="header">X Indicator Section 3</span>
<div slot="content">
<p>Modern accordion indicator style</p>
</div>
</ag-accordion-item>
</ag-accordion>
</div>
<div class="mbe4">
<h2>Plus/Minus Indicator</h2>
<p class="mbe2" style="color: var(--ag-text-secondary); font-size: 0.875rem;">
Plus transitions to minus when open with smooth animation.
</p>
</div>
<div class="stacked mbe4">
<ag-accordion>
<ag-accordion-item use-minus>
<span slot="header">Plus/Minus Section 1</span>
<div slot="content">
<p>Plus changes to minus when opened</p>
</div>
</ag-accordion-item>
<ag-accordion-item use-minus>
<span slot="header">Plus/Minus Section 2</span>
<div slot="content">
<p>Classic expand/collapse indicator</p>
</div>
</ag-accordion-item>
<ag-accordion-item use-minus>
<span slot="header">Plus/Minus Section 3</span>
<div slot="content">
<p>Clear visual indication of state</p>
</div>
</ag-accordion-item>
</ag-accordion>
</div>
<div class="mbe4">
<h2>No Indicator</h2>
<p class="mbe2" style="color: var(--ag-text-secondary); font-size: 0.875rem;">
Accordion items without any visual indicator.
</p>
</div>
<div class="stacked mbe4">
<ag-accordion>
<ag-accordion-item no-indicator>
<span slot="header">No Indicator Section 1</span>
<div slot="content">
<p>Clean header without indicator icon</p>
</div>
</ag-accordion-item>
<ag-accordion-item no-indicator>
<span slot="header">No Indicator Section 2</span>
<div slot="content">
<p>Minimal design focused on content</p>
</div>
</ag-accordion-item>
<ag-accordion-item no-indicator>
<span slot="header">No Indicator Section 3</span>
<div slot="content">
<p>Simple accordion without visual clutter</p>
</div>
</ag-accordion-item>
</ag-accordion>
</div>
<div class="mbe4">
<h2>Bordered</h2>
</div>
<div class="stacked mbe4">
<ag-accordion>
<ag-accordion-item bordered use-chevron>
<span slot="header">Bordered Item 1</span>
<div slot="content">
<p>This accordion has borders on the headers</p>
</div>
</ag-accordion-item>
<ag-accordion-item bordered use-chevron>
<span slot="header">Bordered Item 2</span>
<div slot="content">
<p>Another bordered item</p>
</div>
</ag-accordion-item>
<ag-accordion-item bordered use-chevron>
<span slot="header">Bordered Item 3</span>
<div slot="content">
<p>Third bordered item</p>
</div>
</ag-accordion-item>
</ag-accordion>
</div>
<div class="mbe4">
<h2>With Background</h2>
</div>
<div class="stacked mbe4">
<ag-accordion>
<ag-accordion-item background use-chevron>
<span slot="header">Background Item 1</span>
<div slot="content">
<p>This accordion has background color on headers</p>
</div>
</ag-accordion-item>
<ag-accordion-item background use-chevron>
<span slot="header">Background Item 2</span>
<div slot="content">
<p>Another item with background</p>
</div>
</ag-accordion-item>
<ag-accordion-item background use-chevron>
<span slot="header">Background Item 3</span>
<div slot="content">
<p>Third item with background</p>
</div>
</ag-accordion-item>
</ag-accordion>
</div>
<div class="mbe4">
<h2>One Item Open</h2>
</div>
<div class="stacked mbe4">
<ag-accordion>
<ag-accordion-item use-chevron>
<span slot="header">Closed Item</span>
<div slot="content">
<p>This item starts closed</p>
</div>
</ag-accordion-item>
<ag-accordion-item use-chevron open>
<span slot="header">Open Item</span>
<div slot="content">
<p>This item starts open</p>
</div>
</ag-accordion-item>
<ag-accordion-item use-chevron>
<span slot="header">Another Closed Item</span>
<div slot="content">
<p>This item also starts closed</p>
</div>
</ag-accordion-item>
</ag-accordion>
</div>
<div class="mbe4">
<h2>Disabled State</h2>
</div>
<div class="stacked mbe4">
<ag-accordion>
<ag-accordion-item use-chevron>
<span slot="header">Enabled Item</span>
<div slot="content">
<p>This item can be toggled</p>
</div>
</ag-accordion-item>
<ag-accordion-item use-chevron disabled>
<span slot="header">Disabled Item</span>
<div slot="content">
<p>This item cannot be toggled</p>
</div>
</ag-accordion-item>
<ag-accordion-item use-chevron>
<span slot="header">Another Enabled Item</span>
<div slot="content">
<p>This item can also be toggled</p>
</div>
</ag-accordion-item>
</ag-accordion>
</div>
<div class="mbe4">
<h2>Rich Content</h2>
</div>
<div class="stacked mbe4">
<ag-accordion>
<ag-accordion-item use-chevron bordered>
<span slot="header">
<div class="flex-inline items-center">
<svg
class="mie2"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="var(--ag-primary)"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="10" />
<path d="M12 16v-4" />
<path d="M12 8h.01" />
</svg>
Features
</div>
</span>
<div slot="content">
<ul>
<li>Accessible by default with ARIA attributes</li>
<li>Keyboard navigation support</li>
<li>Customizable heading levels</li>
<li>Multiple styling options</li>
</ul>
</div>
</ag-accordion-item>
<ag-accordion-item use-chevron bordered>
<span slot="header">
<div class="flex-inline items-center">
<svg
class="mie2"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="var(--ag-secondary)"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="16 18 22 12 16 6" />
<polyline points="8 6 2 12 8 18" />
</svg>
Code Example
</div>
</span>
<div slot="content">
<pre style="background: var(--ag-background-secondary); padding: 1rem; border-radius: 4px; overflow-x: auto;">
<ag-accordion-item use-chevron>
<span slot="header">Title</span>
<div slot="content">Content</div>
</ag-accordion-item></pre>
</div>
</ag-accordion-item>
<ag-accordion-item use-chevron bordered>
<span slot="header">
<div class="flex-inline items-center">
<svg
class="mie2"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="var(--ag-success)"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="10" />
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
<path d="M12 17h.01" />
</svg>
More Information
</div>
</span>
<div slot="content">
<p>Accordions are great for:</p>
<ul>
<li>FAQ sections</li>
<li>Feature lists</li>
<li>Documentation</li>
<li>Progressive disclosure</li>
</ul>
</div>
</ag-accordion-item>
</ag-accordion>
</div>
<div class="mbe4">
<h2>CSS Parts Customization</h2>
<p class="mbe2" style="color: var(--ag-text-secondary); font-size: 0.875rem;">
Customize accordion appearance using CSS Shadow Parts without
breaking encapsulation.
</p>
</div>
<div class="stacked mbe4">
<ag-accordion>
<ag-accordion-item class="custom-minimal-accordion" use-chevron>
<span slot="header">Minimal Border Style</span>
<div slot="content">
<p>
This variant uses a minimal border-left design with subtle
styling.
</p>
</div>
</ag-accordion-item>
<ag-accordion-item class="custom-minimal-accordion" use-chevron>
<span slot="header">Another Minimal Item</span>
<div slot="content">
<p>Clean and simple styling focused on content hierarchy.</p>
</div>
</ag-accordion-item>
</ag-accordion>
</div>
<style>
/* CSS Parts customization examples */
.custom-minimal-accordion::part(ag-accordion-header-wrapper) {
border-left: 4px solid var(--ag-primary);
padding-left: 12px;
}
.custom-minimal-accordion::part(ag-accordion-header) {
font-weight: 500;
color: var(--ag-text-primary);
}
.custom-minimal-accordion::part(ag-accordion-content) {
padding-left: 16px;
border-left: 2px solid #e5e7eb;
margin-left: 2px;
}
.custom-minimal-accordion::part(ag-accordion-indicator) {
color: var(--ag-primary);
}
</style>
</section>
`;
}
}
customElements.define('accordion-lit-examples', AccordionLitExamples);
Interactive Preview: Click the "Open in StackBlitz" button below to see this example running live in an interactive playground.
View React Code
import {
ReactAccordion,
AccordionItem,
ItemHeader,
ItemContent,
} from "agnosticui-core/accordion/react";
export default function AccordionReactExamples() {
return (
<section>
<div className="mbe4">
<h2>Basic Accordion (Default)</h2>
<p
className="mbe2"
style={{ color: "var(--ag-text-secondary)", fontSize: "0.875rem" }}
>
By default, the Accordion provides a chevron which points down when
closed, then rotates 180° to point up when open. See below for how to
opt out or use different indicators.
</p>
</div>
<div className="stacked mbe4">
<ReactAccordion>
<AccordionItem useChevron>
<ItemHeader>Chevron Section 1</ItemHeader>
<ItemContent>
<p>Default chevron indicator with smooth rotation</p>
</ItemContent>
</AccordionItem>
<AccordionItem useChevron>
<ItemHeader>Chevron Section 2</ItemHeader>
<ItemContent>
<p>Click to see the 180° rotation animation</p>
</ItemContent>
</AccordionItem>
<AccordionItem useChevron>
<ItemHeader>Chevron Section 3</ItemHeader>
<ItemContent>
<p>Classic accordion indicator style</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
</div>
<div className="mbe4">
<h2>X Indicator</h2>
<p
className="mbe2"
style={{ color: "var(--ag-text-secondary)", fontSize: "0.875rem" }}
>
Plus rotated 180° (upside down) when closed, rotates to 45° forming
an X when open.
</p>
</div>
<div className="stacked mbe4">
<ReactAccordion>
<AccordionItem useX>
<ItemHeader>X Indicator Section 1</ItemHeader>
<ItemContent>
<p>Plus transforms into X when opened</p>
</ItemContent>
</AccordionItem>
<AccordionItem useX>
<ItemHeader>X Indicator Section 2</ItemHeader>
<ItemContent>
<p>Smooth transition from plus to X</p>
</ItemContent>
</AccordionItem>
<AccordionItem useX>
<ItemHeader>X Indicator Section 3</ItemHeader>
<ItemContent>
<p>Modern accordion indicator style</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
</div>
<div className="mbe4">
<h2>Plus/Minus Indicator</h2>
<p
className="mbe2"
style={{ color: "var(--ag-text-secondary)", fontSize: "0.875rem" }}
>
Plus transitions to minus when open with smooth animation.
</p>
</div>
<div className="stacked mbe4">
<ReactAccordion>
<AccordionItem useMinus>
<ItemHeader>Plus/Minus Section 1</ItemHeader>
<ItemContent>
<p>Plus changes to minus when opened</p>
</ItemContent>
</AccordionItem>
<AccordionItem useMinus>
<ItemHeader>Plus/Minus Section 2</ItemHeader>
<ItemContent>
<p>Classic expand/collapse indicator</p>
</ItemContent>
</AccordionItem>
<AccordionItem useMinus>
<ItemHeader>Plus/Minus Section 3</ItemHeader>
<ItemContent>
<p>Clear visual indication of state</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
</div>
<div className="mbe4">
<h2>No Indicator</h2>
<p
className="mbe2"
style={{ color: "var(--ag-text-secondary)", fontSize: "0.875rem" }}
>
Accordion items without any visual indicator.
</p>
</div>
<div className="stacked mbe4">
<ReactAccordion>
<AccordionItem noIndicator>
<ItemHeader>No Indicator Section 1</ItemHeader>
<ItemContent>
<p>Clean header without indicator icon</p>
</ItemContent>
</AccordionItem>
<AccordionItem noIndicator>
<ItemHeader>No Indicator Section 2</ItemHeader>
<ItemContent>
<p>Minimal design focused on content</p>
</ItemContent>
</AccordionItem>
<AccordionItem noIndicator>
<ItemHeader>No Indicator Section 3</ItemHeader>
<ItemContent>
<p>Simple accordion without visual clutter</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
</div>
<div className="mbe4">
<h2>Bordered</h2>
</div>
<div className="stacked mbe4">
<ReactAccordion>
<AccordionItem bordered useChevron>
<ItemHeader>Bordered Item 1</ItemHeader>
<ItemContent>
<p>This accordion has borders on the headers</p>
</ItemContent>
</AccordionItem>
<AccordionItem bordered useChevron>
<ItemHeader>Bordered Item 2</ItemHeader>
<ItemContent>
<p>Another bordered item</p>
</ItemContent>
</AccordionItem>
<AccordionItem bordered useChevron>
<ItemHeader>Bordered Item 3</ItemHeader>
<ItemContent>
<p>Third bordered item</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
</div>
<div className="mbe4">
<h2>With Background</h2>
</div>
<div className="stacked mbe4">
<ReactAccordion>
<AccordionItem background useChevron>
<ItemHeader>Background Item 1</ItemHeader>
<ItemContent>
<p>This accordion has background color on headers</p>
</ItemContent>
</AccordionItem>
<AccordionItem background useChevron>
<ItemHeader>Background Item 2</ItemHeader>
<ItemContent>
<p>Another item with background</p>
</ItemContent>
</AccordionItem>
<AccordionItem background useChevron>
<ItemHeader>Background Item 3</ItemHeader>
<ItemContent>
<p>Third item with background</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
</div>
<div className="mbe4">
<h2>One Item Open</h2>
</div>
<div className="stacked mbe4">
<ReactAccordion>
<AccordionItem useChevron>
<ItemHeader>Closed Item</ItemHeader>
<ItemContent>
<p>This item starts closed</p>
</ItemContent>
</AccordionItem>
<AccordionItem useChevron open>
<ItemHeader>Open Item</ItemHeader>
<ItemContent>
<p>This item starts open</p>
</ItemContent>
</AccordionItem>
<AccordionItem useChevron>
<ItemHeader>Another Closed Item</ItemHeader>
<ItemContent>
<p>This item also starts closed</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
</div>
<div className="mbe4">
<h2>Disabled State</h2>
</div>
<div className="stacked mbe4">
<ReactAccordion>
<AccordionItem useChevron>
<ItemHeader>Enabled Item</ItemHeader>
<ItemContent>
<p>This item can be toggled</p>
</ItemContent>
</AccordionItem>
<AccordionItem useChevron disabled>
<ItemHeader>Disabled Item</ItemHeader>
<ItemContent>
<p>This item cannot be toggled</p>
</ItemContent>
</AccordionItem>
<AccordionItem useChevron>
<ItemHeader>Another Enabled Item</ItemHeader>
<ItemContent>
<p>This item can also be toggled</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
</div>
<div className="mbe4">
<h2>Rich Content</h2>
</div>
<div className="stacked mbe4">
<ReactAccordion>
<AccordionItem useChevron bordered>
<ItemHeader>
<div className="flex-inline items-center">
<svg
className="mie2"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="var(--ag-primary)"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="12" cy="12" r="10" />
<path d="M12 16v-4" />
<path d="M12 8h.01" />
</svg>
Features
</div>
</ItemHeader>
<ItemContent>
<ul>
<li>Accessible by default with ARIA attributes</li>
<li>Keyboard navigation support</li>
<li>Customizable heading levels</li>
<li>Multiple styling options</li>
</ul>
</ItemContent>
</AccordionItem>
<AccordionItem useChevron bordered>
<ItemHeader>
<div className="flex-inline items-center">
<svg
className="mie2"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="var(--ag-secondary)"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<polyline points="16 18 22 12 16 6" />
<polyline points="8 6 2 12 8 18" />
</svg>
Code Example
</div>
</ItemHeader>
<ItemContent>
<pre
style={{
background: "var(--ag-background-secondary)",
padding: "1rem",
borderRadius: "4px",
overflowX: "auto",
}}
>
{`<AccordionItem useChevron>
<ItemHeader>Title</ItemHeader>
<ItemContent>Content</ItemContent>
</AccordionItem>`}
</pre>
</ItemContent>
</AccordionItem>
<AccordionItem useChevron bordered>
<ItemHeader>
<div className="flex-inline items-center">
<svg
className="mie2"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="var(--ag-success)"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="12" cy="12" r="10" />
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
<path d="M12 17h.01" />
</svg>
More Information
</div>
</ItemHeader>
<ItemContent>
<p>Accordions are great for:</p>
<ul>
<li>FAQ sections</li>
<li>Feature lists</li>
<li>Documentation</li>
<li>Progressive disclosure</li>
</ul>
</ItemContent>
</AccordionItem>
</ReactAccordion>
</div>
<div className="mbe4">
<h2>CSS Parts Customization</h2>
<p
className="mbe2"
style={{ color: "var(--ag-text-secondary)", fontSize: "0.875rem" }}
>
Customize accordion appearance using CSS Shadow Parts without
breaking encapsulation.
</p>
</div>
<div className="stacked mbe4">
<ReactAccordion>
<AccordionItem className="custom-minimal-accordion" useChevron>
<ItemHeader>Minimal Border Style</ItemHeader>
<ItemContent>
<p>
This variant uses a minimal border-left design with subtle
styling.
</p>
</ItemContent>
</AccordionItem>
<AccordionItem className="custom-minimal-accordion" useChevron>
<ItemHeader>Another Minimal Item</ItemHeader>
<ItemContent>
<p>Clean and simple styling focused on content hierarchy.</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
</div>
{/* CSS Parts customization styles */}
<style>{`
.custom-minimal-accordion::part(ag-accordion-header-wrapper) {
border-left: 4px solid var(--ag-primary);
padding-left: 12px;
}
.custom-minimal-accordion::part(ag-accordion-header) {
font-weight: 500;
color: var(--ag-text-primary);
}
.custom-minimal-accordion::part(ag-accordion-content) {
padding-left: 16px;
border-left: 2px solid #e5e7eb;
margin-left: 2px;
}
.custom-minimal-accordion::part(ag-accordion-indicator) {
color: var(--ag-primary);
}
`}</style>
</section>
);
}
Usage
TIP
The framework examples below import AgnosticUI as an npm package. Alternatively, you can use the CLI for complete control, AI/LLM visibility, and full code ownership:
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add AccordionThe CLI copies source code directly into your project, giving you full visibility and control. After running npx ag add, you'll receive exact import instructions.
Vue
<template>
<section>
<VueAccordion>
<VueAccordionItem>
<VueAccordionHeader>Accordion Item 1</VueAccordionHeader>
<VueAccordionContent>
<p>This is the content of the first accordion item.</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem>
<VueAccordionHeader>Accordion Item 2</VueAccordionHeader>
<VueAccordionContent>
<p>This is the content of the second accordion item.</p>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem>
<VueAccordionHeader>Accordion Item 3</VueAccordionHeader>
<VueAccordionContent>
<p>This is the content of the third accordion item.</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
<VueAccordion>
<VueAccordionItem use-chevron bordered>
<VueAccordionHeader>Features</VueAccordionHeader>
<VueAccordionContent>
<ul>
<li>Accessible by default</li>
<li>Keyboard navigation support</li>
<li>Customizable heading levels</li>
</ul>
</VueAccordionContent>
</VueAccordionItem>
<VueAccordionItem use-chevron bordered open>
<VueAccordionHeader>Open by Default</VueAccordionHeader>
<VueAccordionContent>
<p>This item starts in the open state.</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
<VueAccordion>
<VueAccordionItem use-x @toggle="handleToggle">
<VueAccordionHeader>X Indicator</VueAccordionHeader>
<VueAccordionContent>
<p>Plus icon that transforms into an X when opened</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
<VueAccordion>
<VueAccordionItem use-minus @toggle="handleToggle">
<VueAccordionHeader>Plus/Minus Indicator</VueAccordionHeader>
<VueAccordionContent>
<p>Plus icon that changes to minus when opened</p>
</VueAccordionContent>
</VueAccordionItem>
</VueAccordion>
</section>
</template>
<script>
import VueAccordion, {
VueAccordionItem,
VueAccordionHeader,
VueAccordionContent,
} from "agnosticui-core/accordion/vue";
export default {
components: {
VueAccordion,
VueAccordionItem,
VueAccordionHeader,
VueAccordionContent,
},
methods: {
handleToggle(detail) {
console.log("Accordion toggled:", detail.open);
},
},
};
</script>React
import {
ReactAccordion,
AccordionItem,
ItemHeader,
ItemContent,
} from "agnosticui-core/accordion/react";
export default function AccordionExample() {
const handleToggle = (event: CustomEvent) => {
console.log("Accordion toggled:", event.detail.open);
};
return (
<section>
<ReactAccordion>
<AccordionItem>
<ItemHeader>Accordion Item 1</ItemHeader>
<ItemContent>
<p>This is the content of the first accordion item.</p>
</ItemContent>
</AccordionItem>
<AccordionItem>
<ItemHeader>Accordion Item 2</ItemHeader>
<ItemContent>
<p>This is the content of the second accordion item.</p>
</ItemContent>
</AccordionItem>
<AccordionItem>
<ItemHeader>Accordion Item 3</ItemHeader>
<ItemContent>
<p>This is the content of the third accordion item.</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
<ReactAccordion>
<AccordionItem useChevron bordered>
<ItemHeader>Features</ItemHeader>
<ItemContent>
<ul>
<li>Accessible by default</li>
<li>Keyboard navigation support</li>
<li>Customizable heading levels</li>
</ul>
</ItemContent>
</AccordionItem>
<AccordionItem useChevron bordered open={true}>
<ItemHeader>Open by Default</ItemHeader>
<ItemContent>
<p>This item starts in the open state.</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
<ReactAccordion>
<AccordionItem useX onToggle={handleToggle}>
<ItemHeader>X Indicator</ItemHeader>
<ItemContent>
<p>Plus icon that transforms into an X when opened</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
<ReactAccordion>
<AccordionItem useMinus onToggle={handleToggle}>
<ItemHeader>Plus/Minus Indicator</ItemHeader>
<ItemContent>
<p>Plus icon that changes to minus when opened</p>
</ItemContent>
</AccordionItem>
</ReactAccordion>
</section>
);
}Lit (Web Components)
import { LitElement, html, css } from 'lit';
import { customElement } from 'lit/decorators.js';
import 'agnosticui-core/accordion';
@customElement('accordion-example')
export class AccordionExample extends LitElement {
static styles = css`
:host {
display: block;
}
section {
display: flex;
flex-direction: column;
gap: 2rem;
}
`;
firstUpdated() {
// Set up event listeners for accordion items in the shadow DOM
const items = this.shadowRoot?.querySelectorAll('ag-accordion-item');
items?.forEach((item) => {
item.addEventListener('toggle', (event: Event) => {
const customEvent = event as CustomEvent;
console.log('Accordion toggled:', customEvent.detail.open);
});
});
}
render() {
return html`
<section>
<ag-accordion>
<ag-accordion-item>
<span slot="header">Accordion Item 1</span>
<div slot="content">
<p>This is the content of the first accordion item.</p>
</div>
</ag-accordion-item>
<ag-accordion-item>
<span slot="header">Accordion Item 2</span>
<div slot="content">
<p>This is the content of the second accordion item.</p>
</div>
</ag-accordion-item>
<ag-accordion-item>
<span slot="header">Accordion Item 3</span>
<div slot="content">
<p>This is the content of the third accordion item.</p>
</div>
</ag-accordion-item>
</ag-accordion>
<ag-accordion>
<ag-accordion-item use-chevron bordered>
<span slot="header">Features</span>
<div slot="content">
<ul>
<li>Accessible by default</li>
<li>Keyboard navigation support</li>
<li>Customizable heading levels</li>
</ul>
</div>
</ag-accordion-item>
<ag-accordion-item use-chevron bordered open>
<span slot="header">Open by Default</span>
<div slot="content">
<p>This item starts in the open state.</p>
</div>
</ag-accordion-item>
</ag-accordion>
<ag-accordion>
<ag-accordion-item id="x-indicator-item" use-x>
<span slot="header">X Indicator</span>
<div slot="content">
<p>Plus icon that transforms into an X when opened</p>
</div>
</ag-accordion-item>
</ag-accordion>
<ag-accordion>
<ag-accordion-item id="minus-indicator-item" use-minus>
<span slot="header">Plus/Minus Indicator</span>
<div slot="content">
<p>Plus icon that changes to minus when opened</p>
</div>
</ag-accordion-item>
</ag-accordion>
</section>
`;
}
}Note: When using accordion components within a custom element's shadow DOM, set up event listeners in the component's lifecycle (e.g., firstUpdated()) using this.shadowRoot.querySelectorAll() instead of document.addEventListener('DOMContentLoaded', ...).
Props
Accordion (Container)
The Accordion component is a simple container with no specific props. It wraps multiple AccordionItem components.
AccordionItem
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | false | Whether the accordion item is expanded |
headingLevel | number | 3 | Heading level for semantic HTML (1-6, renders as h1-h6) |
disabled | boolean | false | Whether the accordion item is disabled |
useChevron | boolean | true | Use chevron indicator (default) - rotates 180° when open |
useX | boolean | false | Use X indicator - plus rotated 180° initially, becomes X at 45° when open |
useMinus | boolean | false | Use plus/minus indicator - plus transitions to minus when open |
noIndicator | boolean | false | Hide the indicator completely |
bordered | boolean | false | Whether to apply border styling to the header |
background | boolean | false | Whether to apply background color to the header |
Note: Indicator props are mutually exclusive with priority: noIndicator > useX > useMinus > useChevron (default)
Events
The AccordionItem component follows AgnosticUI v2 event conventions with dual-dispatch for the toggle custom event - you can use either addEventListener or callback props (e.g., onToggle).
| Event | Framework | Detail | Description |
|---|---|---|---|
toggle | Vue: @toggleReact: onToggleLit: @toggle or .onToggle | { open: boolean } | Fired when the accordion item is toggled between open and closed states. |
Event Handling Examples
Vue
<template>
<VueAccordionItem @toggle="handleToggle">
<template #header>Toggle me</template>
<template #content>Content here</template>
</VueAccordionItem>
<VueAccordionItem v-model:open="isOpen">
<template #header>Controlled accordion</template>
<template #content>Content here</template>
</VueAccordionItem>
<VueAccordionItem v-model:open="isOpen" @toggle="handleToggle">
<template #header>Both patterns</template>
<template #content>Content here</template>
</VueAccordionItem>
</template>
<script setup>
import { ref } from "vue";
import { VueAccordionItem } from "agnosticui-core/accordion/vue";
const isOpen = ref(false);
const handleToggle = (detail) => {
console.log("Toggle event:", detail);
};
</script>React
import { useState } from "react";
import {
AccordionItem,
ItemHeader,
ItemContent,
} from "agnosticui-core/accordion/react";
export default function AccordionExample() {
const [isOpen, setIsOpen] = useState(false);
const handleToggle = (event) => {
console.log("Toggle event:", event.detail);
setIsOpen(event.detail.open);
};
return (
<AccordionItem open={isOpen} onToggle={handleToggle}>
<ItemHeader>Click to toggle</ItemHeader>
<ItemContent>Accordion content here</ItemContent>
</AccordionItem>
);
}Lit (Web Components)
<script type="module">
import "agnosticui-core/accordion";
const item = document.querySelector("#my-accordion");
item.addEventListener("toggle", (event) => {
console.log("Toggle event:", event.detail);
});
item.onToggle = (event) => {
console.log("Toggle event (callback):", event.detail);
};
</script>
<ag-accordion-item id="my-accordion">
<span slot="header">Click to toggle</span>
<div slot="content">Accordion content here</div>
</ag-accordion-item>CSS Shadow Parts
The Accordion exposes CSS Shadow Parts that allow you to customize internal elements without breaking encapsulation:
| Part | Description | Element |
|---|---|---|
ag-accordion-wrapper | The main wrapper container | <div> |
ag-accordion-header-wrapper | The header wrapper containing the heading and button | <div> |
ag-accordion-heading | The semantic heading element (h1-h6) | <h1>-<h6> |
ag-accordion-header | The interactive button inside the heading | <button> |
ag-accordion-indicator | The expand/collapse indicator icon wrapper | <span> |
ag-accordion-content | The collapsible content region | <div> |
Example Usage
ag-accordion-item::part(ag-accordion-header-wrapper) {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 8px;
padding: 4px;
}
ag-accordion-item::part(ag-accordion-header) {
color: white;
padding: 16px 20px;
}
ag-accordion-item::part(ag-accordion-content) {
background: #f9fafb;
padding: 20px;
border: 2px solid #e5e7eb;
}
ag-accordion-item::part(ag-accordion-indicator) {
color: #12623e;
}Accessibility
The Accordion implements the WAI-ARIA Accordion Pattern:
- Uses semantic heading elements (h1-h6) with customizable
headingLevelprop - Buttons have
aria-expandedto communicate state - Content panels have
role="region"and are labeled viaaria-labelledby - Keyboard accessible:
- Space/Enter: Toggle the focused accordion item
- Arrow Down: Move focus to next accordion item
- Arrow Up: Move focus to previous accordion item
- Home: Move focus to first accordion item
- End: Move focus to last accordion item
- Using TAB works as well
- Screen readers announce the current state (expanded/collapsed)
- Clear focus indicators for keyboard navigation
- Disabled items cannot be interacted with and are communicated via
aria-disabled
Progressive Enhancement
The Accordion is designed with progressive enhancement in mind:
- Content is visible by default before JavaScript loads
- Once the web component is defined, expand/collapse functionality is enhanced
- If JavaScript fails to load, users can still access all content
- Uses the
data-enhancedattribute to apply hide/show logic only after JavaScript initialization