Accordion
JavaScript off: what the HTML and CSS do on their own.
Usage
<Accordion>
<AccordionItem Title="How do refunds work?" Open>
Refunds go back to the original card within 5 business days.
</AccordionItem>
<AccordionItem Title="Can I change my plan later?">
Yes. Changes apply from your next billing date.
</AccordionItem>
</Accordion>Each item is a native details element, so the browser opens and closes it, with JavaScript off too. Use it for sections people open one by one, such as FAQs or settings; for a single "show more", use a Collapsible, and for views people switch between, Tabs.
Variants
Use Variant to draw the items as separate cards (the default), as one bordered box, or flush with the page.
Preview
Separated
How do refunds work?
Can I change my plan later?
Bordered
How do refunds work?
Can I change my plan later?
Flush
How do refunds work?
Can I change my plan later?
Code
<Stack Gap="6" Grow>
foreach (var variant in Enum.GetValues<AccordionVariant>())
{
<Stack Gap="2">
<TextBlock Size="TextSize.Sm" Color="Color.Muted">variant</TextBlock>
<Accordion Variant="variant">
<AccordionItem Title="How do refunds work?" Icon="Lucide.CreditCard">
Refunds go back to the original card within 5 business days.
</AccordionItem>
<AccordionItem Title="Can I change my plan later?">
Yes. Changes apply from your next billing date.
</AccordionItem>
</Accordion>
</Stack>
}
</Stack>One open at a time
Use Exclusive to keep one item open: opening another closes it, by the browser, with no script. Disabled stops an item opening.
Preview
Shipping
Returns
Warranty
Gift cards
Code
<Accordion Exclusive Variant="AccordionVariant.Bordered" Grow>
<AccordionItem Title="Shipping" Open>Orders ship within two business days.</AccordionItem>
<AccordionItem Title="Returns">Return anything within 30 days, in its original box.</AccordionItem>
<AccordionItem Title="Warranty">Two years on all hardware, parts and labor.</AccordionItem>
<AccordionItem Title="Gift cards" Disabled>Coming soon.</AccordionItem>
</Accordion>Exclusive items share a name; set Name yourself to group several accordions, so one item is open across all of them.
Rich headers and content
Use an AccordionHeader for a title with more than text, such as a badge, and Icon for an icon before it; the content is a column with a gap, so text, buttons and lists need no wrapper.
Preview
Getting started 2 steps left
Create a project, then invite your team.
You can change these settings later.
Usage this month
- Builds
- 132 of 500
- Storage
- 4.1 GB of 10 GB
Code
<Accordion Variant="AccordionVariant.Bordered" Grow>
<AccordionItem Open>
<AccordionHeader>Getting started <Badge Status="Status.Info" Pill>2 steps left</Badge></AccordionHeader>
<TextBlock>Create a project, then invite your team.</TextBlock>
<TextBlock Size="TextSize.Sm" Color="Color.Muted">You can change these settings later.</TextBlock>
<Row Gap="2">
<Button Size="ControlSize.Sm">Create project</Button>
<Button Size="ControlSize.Sm" Variant="ButtonVariant.Ghost" Accent="Accent.Neutral">Read the guide</Button>
</Row>
</AccordionItem>
<AccordionItem Title="Usage this month">
<DescriptionList Divided>
<DescriptionItem Term="Builds">132 of 500</DescriptionItem>
<DescriptionItem Term="Storage">4.1 GB of 10 GB</DescriptionItem>
</DescriptionList>
</AccordionItem>
</Accordion>ContentPadding and ContentGap change the content's spacing for every item, or on one item; ContentPadding="0" runs a table or image edge to edge.
Sizes
Use Size to scale the titles and spacing together: Sm for sidebars and dense pages, Lg for FAQ pages.
Preview
Billing
Security
Billing
Security
Code
<Grid Columns="new() { Base = 1, Md = 2 }" Gap="6" Align="Align.Start" Grow>
<Accordion Size="ControlSize.Sm" Variant="AccordionVariant.Bordered">
<AccordionItem Title="Billing" Icon="Lucide.CreditCard" Open>Invoices go out on the 1st of the month.</AccordionItem>
<AccordionItem Title="Security" Icon="Lucide.Shield">Two-factor sign-in is on.</AccordionItem>
</Accordion>
<Accordion Size="ControlSize.Lg" Variant="AccordionVariant.Bordered">
<AccordionItem Title="Billing" Icon="Lucide.CreditCard" Open>Invoices go out on the 1st of the month.</AccordionItem>
<AccordionItem Title="Security" Icon="Lucide.Shield">Two-factor sign-in is on.</AccordionItem>
</Accordion>
</Grid>Forms in sections
Use Open on an item to open it from the server, such as the section whose form just posted.
Preview
Profile
Notifications
Code
System.ComponentModel.DataAnnotations
@* Each section's form posts on its own. A static page renders the accordion again with every
post, so the section that posted, saved or not, is opened from the server with Open. *@
<Accordion Variant="AccordionVariant.Bordered" Grow MaxWidth="32.Rem">
<AccordionItem Title="Profile" Open="_posted.Contains(Section.Profile)">
<Form Model="Profile" FormName="accordion-profile" OnValidSubmit="() => Saved(Section.Profile)" OnInvalidSubmit="() => _posted.Add(Section.Profile)">
<TextField @bind-Value="Profile!.DisplayName" />
<FormActions><Button Submit Size="ControlSize.Sm">Save profile</Button></FormActions>
</Form>
</AccordionItem>
<AccordionItem Title="Notifications" Open="_posted.Contains(Section.Notifications)">
<Form Model="Notifications" FormName="accordion-notifications" OnValidSubmit="() => Saved(Section.Notifications)" OnInvalidSubmit="() => _posted.Add(Section.Notifications)">
<Switch @bind-Value="Notifications!.WeeklySummary" />
<FormActions><Button Submit Size="ControlSize.Sm">Save notifications</Button></FormActions>
</Form>
</AccordionItem>
</Accordion>
if (_saved is not null)
{
<TextBlock Size="TextSize.Sm" Color="Color.Muted" MarginTop="3">_saved</TextBlock>
}
{
[SupplyParameterFromForm(FormName = "accordion-profile")]
private ProfileSettings? Profile { get; set; }
[SupplyParameterFromForm(FormName = "accordion-notifications")]
private NotificationSettings? Notifications { get; set; }
// Sections that have posted. Only ever added to, so on an interactive page Open never turns
// false and closes a section the reader left open.
private readonly HashSet<Section> _posted = [];
private string? _saved;
protected override void OnInitialized()
{
Profile ??= new();
Notifications ??= new();
}
private void Saved(Section section)
{
_posted.Add(section);
_saved = section == Section.Profile
? $"Saved your name as {Profile!.DisplayName}."
: $"Saved: {(Notifications!.WeeklySummary ? "with" : "without")} the weekly summary.";
}
}Off: Saving reloads the page: the section that posted, saved or with errors, opens again because the page sets its Open; any other section you opened closes.
The browser keeps which items are open, not the server, so on a static page every post or reload draws them as Open says and closes the rest. Open the section that posted, as here, whether it saved or not (OnInvalidSubmit too), so its message or errors are in view.
Following it from C#
Use @bind-Open on an AccordionItem to know in C# whether it's open, and to open or close it from C#, on an interactive page.
Preview
Release notes
C# has it closed
Code
@* The item opens and closes in every mode; on an interactive page C# follows it. *@
<Stack Gap="3" Grow>
<Accordion>
<AccordionItem Title="Release notes" @bind-Open="_notesOpen">
Version 2.4 adds dark mode to the dashboard and speeds up search.
</AccordionItem>
</Accordion>
<TextBlock Size="TextSize.Sm" Color="Color.Muted">C# has it <Code>(_notesOpen ? "open" : "closed")</Code></TextBlock>
</Stack>
{
private bool _notesOpen;
}Off: The item opens and closes; C# isn't told.
Parts
Written inside Accordion. The API page lists their parameters.
AccordionItem: one section of an Accordion: a native <details> with the title in its <summary>.AccordionHeader: Heading content for an AccordionItem in place of its Title, such as a title with a badge.
Mode support
| Feature | Off | Static | Live |
|---|---|---|---|
| Items open and close, one at a time with Exclusive | Yes | Yes | Yes |
| An item's Open bound to C# | No | No | Yes |
Off: JavaScript disabled. Static: a static SSR page with IzzyBlazor's script. Live: an interactive page (Server, WebAssembly or Auto).
Accessibility
- Each item's
summarytakes Enter and Space and is announced as expanded or collapsed by the browser, with JavaScript off too. - Tab moves from item to item; there are no arrow-key or Home/End shortcuts.
- The title isn't a heading, so items don't appear in a screen reader's list of headings. AccordionHeader is drawn inside the
summary: keep it to inline content, with no links or buttons. - A
Disableditem setsaria-disabledon itssummaryand leaves the tab order; the script also stops it from toggling.
Parameters
| Prop | Type | Default |
|---|---|---|
ExclusiveKeeps only one item open at a time. | bool | false |
VariantHow the items are drawn. | AccordionVariant | AccordionVariant.Separated |
SizeSpacing and title size: ControlSize.Sm for sidebars and dense pages, ControlSize.Lg for FAQ pages. | ControlSize | ControlSize.Md |
ContentPaddingPadding inside every item's content, in spacing steps. | Responsive<int> | |
ContentGapSpace between the children of every item's content, in spacing steps. | Responsive<int> | |
NameThe shared name for exclusive items. | string? | |
ChildContentThe AccordionItems. | RenderFragment? |
Plus 16 item props and 4 common props.
Full APISee also
- Collapsible: one "show more" section.
- Tabs: panels that switch with no script, or links to pages.