Accordion
A vertically stacked set of interactive headings that each reveal an associated section of content.
Demo
Multiple Items Expanded
Allow users to expand multiple items simultaneously using Type="AccordionType.Multiple".
dotnet add package SummitUI to get started.
Disabled Items
Disable specific items to prevent user interaction while keeping them visible.
Non-Collapsible Mode
When Collapsible="false", at least one item must always remain open in single mode.
Controlled Mode
Control the accordion state externally using Value and ValueChanged parameters.
None
Custom Styling Example
Accordion components are completely headless - style them however you want using data attributes and CSS.
data-state, data-disabled, and data-orientation to style based on component state.
Features
- Full keyboard navigation
- Single or multiple expanded items
- Controlled and uncontrolled modes
- Collapsible option for single mode
- Horizontal and vertical orientations
- WCAG compliant with proper ARIA attributes
Installation
dotnet add package SummitUIAnatomy
Import the components and structure them as follows:
<SmAccordionRoot>
<SmAccordionItem Value="item-1">
<SmAccordionHeader>
<SmAccordionTrigger>Title</SmAccordionTrigger>
</SmAccordionHeader>
<SmAccordionContent>
Content goes here...
</SmAccordionContent>
</SmAccordionItem>
</SmAccordionRoot>Sub-components
AccordionRoot
Root container that manages state and provides context to all children.
AccordionItem
Individual collapsible section container with a unique value identifier.
AccordionHeader
Semantic heading wrapper that provides proper heading semantics.
AccordionTrigger
Interactive button that toggles the associated content panel.
AccordionContent
Collapsible content panel that shows/hides based on state.
Enums
AccordionType
Controls whether one or multiple items can be expanded simultaneously.
public enum AccordionType
{
Single, // Only one item can be expanded at a time
Multiple // Multiple items can be expanded simultaneously
}AccordionOrientation
Affects keyboard navigation direction (arrow key behavior).
public enum AccordionOrientation
{
Vertical, // Arrow Up/Down keys navigate between items
Horizontal // Arrow Left/Right keys navigate between items
}API Reference
AccordionRoot
Root container managing accordion state and providing cascading context to all child components.
| Property | Type | Default | Description |
|---|---|---|---|
| Type | AccordionType | Single | Whether one or multiple items can be expanded |
| Value | string? | null | Controlled expanded value (single mode) |
| Values | IReadOnlyList<string>? | null | Controlled expanded values (multiple mode) |
| DefaultValue | string? | null | Default expanded value (uncontrolled, single) |
| DefaultValues | IReadOnlyList<string>? | null | Default expanded values (uncontrolled, multiple) |
| ValueChanged | EventCallback<string?> | - | Callback when value changes (single mode) |
| ValuesChanged | EventCallback<IReadOnlyList<string>> | - | Callback when values change (multiple mode) |
| Orientation | AccordionOrientation | Vertical | Affects keyboard navigation direction |
| Loop | bool | true | Whether keyboard nav loops from last to first |
| Disabled | bool | false | Disable the entire accordion |
| Collapsible | bool | true | Allow closing the last open item (single mode) |
AccordionItem
Individual collapsible section with a unique identifier.
| Property | Type | Default | Description |
|---|---|---|---|
| Valuerequired | string | - | Unique identifier for this accordion item |
| Disabled | bool | false | Disable this specific item |
AccordionHeader
Semantic heading wrapper for proper document structure and accessibility.
| Property | Type | Default | Description |
|---|---|---|---|
| As | string | "h3" | HTML element to render |
| Level | int | 3 | ARIA heading level (1-6) |
AccordionTrigger
Interactive button element that toggles the expansion state of its associated content.
| Property | Type | Default | Description |
|---|---|---|---|
| AsChild | bool | false | Render as a child element instead of button. Child must apply context.Attrs and context.RefCallback. |
AccordionContent
Collapsible content region that expands/collapses based on trigger interaction.
| Property | Type | Default | Description |
|---|---|---|---|
| As | string | "div" | HTML element to render |
| ForceMount | bool | false | Always render in DOM (useful for CSS animations) |
Examples
Basic Usage
<SmAccordionRoot DefaultValue="item-1">
<SmAccordionItem Value="item-1">
<SmAccordionHeader>
<SmAccordionTrigger>What is SummitUI?</SmAccordionTrigger>
</SmAccordionHeader>
<SmAccordionContent>
<p>SummitUI is a Blazor component library focused on accessibility.</p>
</SmAccordionContent>
</SmAccordionItem>
<SmAccordionItem Value="item-2">
<SmAccordionHeader>
<SmAccordionTrigger>Is it accessible?</SmAccordionTrigger>
</SmAccordionHeader>
<SmAccordionContent>
<p>Yes! All components are built with WCAG compliance in mind.</p>
</SmAccordionContent>
</SmAccordionItem>
</SmAccordionRoot>Multiple Expanded Items
Allow multiple items to be expanded simultaneously.
<SmAccordionRoot Type="AccordionType.Multiple"
DefaultValues="@(new[] { "item-1", "item-2" })">
<SmAccordionItem Value="item-1">
<SmAccordionHeader>
<SmAccordionTrigger>First Section</SmAccordionTrigger>
</SmAccordionHeader>
<SmAccordionContent>First content...</SmAccordionContent>
</SmAccordionItem>
<SmAccordionItem Value="item-2">
<SmAccordionHeader>
<SmAccordionTrigger>Second Section</SmAccordionTrigger>
</SmAccordionHeader>
<SmAccordionContent>Second content...</SmAccordionContent>
</SmAccordionItem>
</SmAccordionRoot>Controlled Mode
Control the expanded state externally.
@code {
private string? expandedItem = "item-1";
}
<SmAccordionRoot Value="@expandedItem"
ValueChanged="@(v => expandedItem = v)">
<SmAccordionItem Value="item-1">
<SmAccordionHeader>
<SmAccordionTrigger>Section 1</SmAccordionTrigger>
</SmAccordionHeader>
<SmAccordionContent>Content 1</SmAccordionContent>
</SmAccordionItem>
<SmAccordionItem Value="item-2">
<SmAccordionHeader>
<SmAccordionTrigger>Section 2</SmAccordionTrigger>
</SmAccordionHeader>
<SmAccordionContent>Content 2</SmAccordionContent>
</SmAccordionItem>
</SmAccordionRoot>
<p>Currently expanded: @(expandedItem ?? "None")</p>
<button @@onclick="@(() => expandedItem = "item-2")">Open Section 2</button>Disabled Items
Disable specific accordion items.
<SmAccordionRoot DefaultValue="item-1">
<SmAccordionItem Value="item-1">
<SmAccordionHeader>
<SmAccordionTrigger>Enabled Section</SmAccordionTrigger>
</SmAccordionHeader>
<SmAccordionContent>This section works normally.</SmAccordionContent>
</SmAccordionItem>
<SmAccordionItem Value="item-2" Disabled="true">
<SmAccordionHeader>
<SmAccordionTrigger>Disabled Section</SmAccordionTrigger>
</SmAccordionHeader>
<SmAccordionContent>This content cannot be accessed.</SmAccordionContent>
</SmAccordionItem>
</SmAccordionRoot>AsChild Pattern
Use AsChild="true" to render a custom element instead of the default button. The child element must apply @attributes="context.Attrs" and @ref="context.RefCallback" to receive the required functionality.
<SmAccordionRoot DefaultValue="item-1">
<SmAccordionItem Value="item-1">
<SmAccordionHeader>
<SmAccordionTrigger AsChild="true">
@context =>
{
<!-- Custom div element instead of default button -->
<div role="button"
tabindex="0"
@attributes="context.Attrs"
@ref="context.RefCallback"
class="custom-trigger">
<span class="trigger-icon">▶</span>
<span>Custom Trigger Element</span>
</div>
}
</SmAccordionTrigger>
</SmAccordionHeader>
<SmAccordionContent>
<p>Content with a custom trigger element.</p>
</SmAccordionContent>
</SmAccordionItem>
<SmAccordionItem Value="item-2">
<SmAccordionHeader>
<SmAccordionTrigger AsChild="true">
@context =>
{
<!-- Custom anchor-styled button -->
<a href="#"
@attributes="context.Attrs"
@ref="context.RefCallback"
class="text-blue-600 hover:underline p-2 block">
Click to expand section 2
</a>
}
</SmAccordionTrigger>
</SmAccordionHeader>
<SmAccordionContent>
<p>This trigger looks like a link but behaves as an accordion trigger.</p>
</SmAccordionContent>
</SmAccordionItem>
</SmAccordionRoot>
@code {
// The AsChild pattern gives you complete control over the rendered element
// while maintaining all accordion functionality (keyboard nav, ARIA, etc.)
}Styling
Data Attributes
| Attribute | Values | Description |
|---|---|---|
| data-state | "open" | "closed" | Current expansion state |
| data-disabled | Present when disabled | Indicates disabled state |
| data-orientation | "vertical" | "horizontal" | Current orientation |
CSS Variables
| Variable | Description |
|---|---|
| --summit-accordion-content-height | Measured height of content in pixels |
| --summit-accordion-content-width | Measured width of content in pixels |
CSS Example
/* Trigger styles */
.accordion-trigger {
display: flex;
justify-content: space-between;
width: 100%;
padding: 1rem;
background: transparent;
border: none;
cursor: pointer;
color: rgb(var(--su-foreground));
}
.accordion-trigger[data-state="open"] {
color: rgb(var(--su-primary));
}
.accordion-trigger:hover {
color: rgb(var(--su-primary));
}
.accordion-trigger[data-disabled] {
opacity: 0.5;
cursor: not-allowed;
}
/* Content animation */
.accordion-content {
overflow: hidden;
transition: height 300ms ease-out;
}
.accordion-content[data-state="open"] {
height: var(--summit-accordion-content-height);
}
.accordion-content[data-state="closed"] {
height: 0;
}
/* Chevron rotation */
.accordion-trigger[data-state="open"] .chevron {
transform: rotate(180deg);
}Accessibility
Keyboard Navigation
| Key | Action |
|---|---|
| Enter / Space | Toggle the focused accordion item |
| ArrowDown | Move focus to next trigger (vertical) |
| ArrowUp | Move focus to previous trigger (vertical) |
| ArrowRight | Move focus to next trigger (horizontal) |
| ArrowLeft | Move focus to previous trigger (horizontal) |
| Home | Move focus to first trigger |
| End | Move focus to last trigger |
ARIA Attributes
- AccordionHeader:
Renders with
role="heading"and appropriatearia-level - AccordionTrigger:
Renders as button with
aria-expandedandaria-controls - AccordionContent:
Renders with
role="region"andaria-labelledby