Surfaces
Accordion
The Accordion shows and hides a section of related content behind a header the reader can open and close. It carries a title, an optional description and icons, animates the panel open to whatever height its content needs, and can be driven by binding, by events or by its own Expand, Collapse and Toggle methods - which a callback of its own can refuse before the panel moves. The header is a button inside a heading, wired to the panel the way the WAI-ARIA accordion pattern asks for.
Usage
Every example is live. Open its code to see exactly what produced the component running underneath.
Basic
Title names the section in the header and everything inside the component is the panel the header shows and hides. The accordion starts collapsed; set DefaultIsExpanded to have it open on the first render.Multiple
Description
Description adds a second, quieter line of text beside the title, for the summary of what the panel holds or for the current value of the setting it hides.Icon
IconName (or an Icon for an external icon library) puts a glyph at the start of the header, before the title, so a list of accordions can be scanned by icon.Expander icon
ExpanderIconName and
ExpanderIcon replace it, ExpanderIconPosition moves it to the start of the header,
HideExpanderIcon removes it, and NoExpanderRotation keeps it still. Giving an
ExpandedExpanderIconName swaps the icon for another one while the panel is open, which also
stops the rotation - a swapped icon already reports the state on its own. For an expander that is not an
icon at all, ExpanderTemplate puts any content in its place.
Actions
Actions render beside the header, outside of the toggle button and of the heading that
wraps it, so they can hold interactive elements of their own: a button inside the header would otherwise be
a button nested in a button, which no browser lets the reader reach.
Controlled
IsExpanded a value the page owns, without binding it back, makes the accordion fully
controlled: it never changes state on its own, and OnClick is where the page decides what the
click means. Here one variable holds the open panel, so opening one closes the others and clicking the open
one closes it again.
Binding
@bind-IsExpanded keeps the state of the accordion and a field of the page in step in both
directions, so the panel can be opened from elsewhere and every toggle is written back. A disabled accordion
(IsEnabled="false") ignores the pointer and the keyboard, and reports itself as disabled to
assistive technology, but the binding still drives it.
Events
OnClick reports every click on the header, whether or not it changed anything.
OnChange reports the new state, and OnExpand and OnCollapse report
each half of it on its own, so a panel that loads its data when it opens does not have to test the flag.
All three report a change that has already happened; OnToggling is
the one that runs before it and can still refuse it.
Cancelling a toggle
OnToggling runs before the panel moves and can refuse the change: set Cancel
on the arguments it hands over and the accordion stays where it is, with nothing written back to the
binding and neither OnChange nor OnExpand/OnCollapse raised.
IsExpanding tells an expansion from a collapse and Reason tells a click on
the header from an Expand, Collapse or Toggle call. The
callback is awaited, so it can load the panel or ask for a confirmation first - nothing else toggles
the accordion while it is running, and the header reports itself as busy for as long as it does.
Programmatic control
Expand, Collapse and Toggle,
which report the change through the binding and the events exactly as a click on the header would. They
work on a disabled accordion too, so an app can still open one to show why it is disabled.
FocusAsync moves the keyboard to the header, so a panel the app has just opened is also
where the reader is standing - and the other way round, a panel that closes on the element the keyboard
was in hands the focus back to its own header on its own, whoever closed it.
Content rendering
LazyContent holds
the first render back until the panel is opened, and then keeps it: the right choice for a heavy panel that
should not cost anything until it is asked for. UnmountOnCollapse goes further and drops the
content again on every collapse, which stops whatever it was running but leaves nothing to animate on the
way out. A collapsed panel is hidden from the reader either way, so its text is out of reach of the
find-in-page of the browser whichever of the three is chosen - and only the first of the three can
still be printed, since the other two have nothing in the DOM
to print.
MaxHeight
MaxHeight (any CSS length) caps how tall the open panel grows and lets its content scroll
inside instead, so a long panel cannot push the rest of the page out of reach. The scrolling region takes a
tab stop of its own, so it can be scrolled from the keyboard as well.
Transition
TransitionDuration (in
milliseconds) overrides the duration the theme provides, and 0 turns the animation off. A
reader who asks for reduced motion gets no animation either way, unless the component opts out of that with
ForceAnimation.
Templates
TitleTemplate takes the place of the title text and leaves the rest of the header - the icon,
the description and the expander - as it is. ExpanderTemplate does the same for the expander,
receiving the current expanded state and sitting inside the wrapper the rotation is applied to, so its
content still turns over unless NoExpanderRotation keeps it still.
HeaderTemplate goes further and replaces the whole header, expander included, receiving the
expanded state so the template can draw its own indicator. Anything interactive belongs in
Actions rather than in any of the three, all of which are rendered inside the toggle button.
The panel itself takes any content at all.




Accessibility
aria-controls and aria-expanded - the structure the WAI-ARIA
accordion pattern asks for. HeadingLevel is what puts the header at the right depth of the
heading outline of the page (3 by default, clamped to 1..6), so the accordions of a section sit one level
below the heading that introduces them; an accordion nested in the panel of another one takes the level
below its own without being told. A collapsed panel is taken out of the tab order and out of the
accessibility tree, so nothing inside a closed accordion answers Tab. A header that does not name itself -
an icon-only HeaderTemplate - takes a HeaderAriaLabel, which names both the toggle
and the panel it opens. NoContentRegion drops the landmark role from the panel, which the
authoring practices ask for on a page carrying more than about six panels that can all be open at once,
where the landmarks would get in the way rather than help. A panel that cannot be closed because
something has to stay open reports itself as aria-disabled through
ReadOnly, which is the state the authoring practices ask for
there rather than the greying-out of IsEnabled="false".
A link the Tab key only reaches while this panel is open.
NoBorder
NoBorder drops the border of the accordion and fills it with the secondary background instead, for a flat accordion that leans on the surface it sits on rather than on an outline.Printing
ExpandOnPrint opens the panel for the print stylesheet
alone - what is on screen stays exactly where the reader left it - and lifts the scroll cap of
MaxHeight with it, since paper does not scroll. What is not in the DOM at all cannot be
printed by any of this: a LazyContent panel that has never been opened, and every closed
panel of an accordion using UnmountOnCollapse, still print as a bare header.
Read-only
ReadOnly is for the panel that has to stay as it is rather than the one that is turned
off: the header keeps the colors of a live one and its place in the tab order, and reports itself as
aria-disabled the way the authoring practices ask an open panel that cannot be closed
to - the last one left open in a one-at-a-time accordion, for instance. OnClick still
reports the click, so the page can say why nothing moved, and Expand,
Collapse and Toggle still drive it: what is closed is the way in from the
header, not the one the app itself uses. Compare it with IsEnabled="false" beside it,
which greys the whole accordion out and takes the header out of the tab order altogether.
Color
Background and Border pick the color kind of the surface and of the outline of the accordion, so it can be tuned to the surface it is placed on - Transparent letting whatever is underneath show through.External Icons
Icon and ExpanderIcon take a BitIconInfo rather than the name of a
built-in icon, so an accordion can be dressed in the icons of any library that draws them from CSS classes.
BitIconInfo.Css takes the classes as they are - a bare string is enough, as the first accordion
below shows - while BitIconInfo.Fa and BitIconInfo.Bi spell out the prefixes of
FontAwesome and Bootstrap Icons for you.
Size
Size drives the padding of the header and of the panel and the type scale of the whole accordion - the title, the description, the icons and the text of the panel - so it can be tuned to how much room it is given.Style & Class
Style and Class dress the root element, while Styles and
Classes reach each part of the accordion on its own - the header, the title, the expander
icon, the panel and everything between them. Two of their slots are states rather than parts:
Expanded is added to the root only while the panel is open, and ExpandedIcon
only to the expander icon while it is, so the open accordion can be dressed differently from the
closed one without a line of C#.
RTL
Dir to BitDir.Rtl - or let it cascade from an ancestor - and the whole header turns around: the icon leads from the right, the expander closes on the left, and the padding of the panel follows with it.API
Every parameter, public member, sub-class and enum this component exposes.
BitAccordion parameters
| Name | Type | Default value | Description |
|---|---|---|---|
| Actions | RenderFragment? | null | The content rendered beside the header, outside of the toggle button and of the heading it sits in, so that it can hold its own interactive elements (a menu, a delete button, a switch). |
| Background | BitColorKind? | null | The color kind of the background of the accordion. |
| Border | BitColorKind? | null | The color kind of the border of the accordion. |
| Body | RenderFragment? | null | Alias for the ChildContent parameter. |
| Busy | bool | false | Reports the header as busy - aria-busy for a screen reader, a busy cursor for a pointer - while something the page is doing on the accordion's behalf is still running. An accordion whose own OnToggling is being awaited reports itself as busy without being told to. |
| Classes | BitAccordionClassStyles? | null | Custom CSS classes for different parts of the accordion. |
| ChildContent | RenderFragment? | null | The content of the accordion. |
| DefaultIsExpanded | bool? | null | Default value for the IsExpanded parameter. |
| Description | string? | null | A short description in the header of the accordion. |
| ExpandedExpanderIcon | BitIconInfo? | null | Gets or sets the icon to show in place of the expander icon while the accordion is expanded, using custom CSS classes for external icon libraries. Takes precedence over ExpandedExpanderIconName when both are set. Setting either of them also turns the rotation of the expander icon off. |
| ExpandedExpanderIconName | string? | null | Gets or sets the name of the icon, from the built-in Fluent UI icons, to show in place of the expander icon while the accordion is expanded. Setting it also turns the rotation of the expander icon off. |
| ExpanderIcon | BitIconInfo? | null | Gets or sets the icon to display as expander using custom CSS classes for external icon libraries. Takes precedence over ExpanderIconName when both are set. Defaults to the ChevronRight icon if neither property is set. |
| ExpanderIconName | string? | null | Gets or sets the name of the icon to display as expander from the built-in Fluent UI icons. Defaults to ChevronRight if not set. |
| ExpanderIconPosition | BitIconPosition? | null | Gets or sets the side of the header the expander icon sits on. The default value is End. |
| ExpanderTemplate | RenderFragment<bool>? | null | The custom content to render in place of the expander icon, leaving the rest of the header as it is and receiving the current expanded state. It sits inside the wrapper the rotation is applied to, so it still turns over unless NoExpanderRotation keeps it still, and HideExpanderIcon still removes it. HeaderTemplate replaces it along with the rest of the header. |
| ExpandOnPrint | bool | false | Opens the panel of the accordion while the page is being printed, so that a collapsed section is not left out of the paper as a bare header. The scroll cap of MaxHeight is lifted along with it. Content that is not in the DOM at all - a LazyContent panel that has never been opened, a collapsed UnmountOnCollapse panel - is still printed as a bare header. |
| HeaderAriaLabel | string? | null | Gets or sets the accessible label of the toggle button in the header, for a header whose own content does not name it - an icon-only HeaderTemplate, most of all. |
| HeaderTemplate | RenderFragment<bool>? | null | Used to customize the header of the accordion. It replaces the whole default header, the expander icon included, and receives the current expanded state. |
| HeadingLevel | int? | null | Gets or sets the heading level (aria-level) reported for the header of the accordion, so that it takes its right place in the heading outline of the page. The default value is 3 - or one level below the accordion this one is nested in - and the value is clamped to the 1..6 range. |
| HideExpanderIcon | bool | false | Removes the expander icon from the header of the accordion. |
| Icon | BitIconInfo? | null | Gets or sets the icon to display at the start of the header using custom CSS classes for external icon libraries. Takes precedence over IconName when both are set. |
| IconName | string? | null | Gets or sets the name of the icon to display at the start of the header from the built-in Fluent UI icons. |
| IsExpanded | bool | false | Determines whether the accordion is expanded or collapsed. (two-way bound) |
| LazyContent | bool | false | Delays the first render of the content of the accordion until it is expanded for the first time. The content stays in the DOM afterwards, so the state it holds survives a collapse. |
| MaxHeight | string? | null | Gets or sets the maximum height of the content of the accordion (any CSS length), beyond which the content scrolls inside the accordion instead of growing it. The scrolling region is focusable, so that it can be scrolled by the keyboard as well. |
| NoBorder | bool | false | Removes the default border of the accordion and gives a background color to the body. |
| NoContentRegion | bool | false | Removes the region role from the panel of the accordion, leaving it a plain container. The role names the panel as a landmark, which helps a screen reader user find their way back to the content of a panel that holds headings or another accordion; the WAI-ARIA authoring practices ask for it to be dropped where it would flood the page with landmarks instead - more than about six panels that can all be open at the same time. |
| NoExpanderRotation | bool | false | Keeps the expander icon still instead of turning it over when the accordion is expanded. |
| OnClick | EventCallback<MouseEventArgs> | Callback that is called when the header is clicked. | |
| OnChange | EventCallback<bool> | Callback that is called when the IsExpanded value has changed. | |
| OnCollapse | EventCallback | Callback that is called when the accordion is collapsed. | |
| OnExpand | EventCallback | Callback that is called when the accordion is expanded. | |
| OnToggling | EventCallback<BitAccordionToggleArgs> | Callback invoked before the accordion expands or collapses, letting the change be cancelled. Since the callback is awaited, it can also run asynchronous work like loading the content of the panel or asking for a confirmation first, and nothing else toggles the accordion while it is running. A change that comes from the IsExpanded parameter itself is not offered here. | |
| ReadOnly | bool | false | Leaves the accordion where it is: the header keeps its colors and its place in the tab order, and reports itself as aria-disabled, but it no longer answers the pointer or the keyboard. OnClick still reports the click, and the Expand, Collapse and Toggle methods still drive the accordion. |
| Size | BitSize? | null | Gets or sets the size of the accordion, which drives the padding of the header and of the panel and the type scale of the whole component. The default value is Medium. |
| Styles | BitAccordionClassStyles? | null | Custom CSS styles for different parts of the accordion. |
| Title | string? | null | Title in the header of Accordion. |
| TitleTemplate | RenderFragment? | null | The custom content to render in place of the Title, leaving the rest of the header - the icon, the description and the expander - as it is. Unlike HeaderTemplate, which replaces the whole header, this only takes the place of the title text. |
| TransitionDuration | int? | null | Gets or sets the duration of the expand/collapse transition in milliseconds, overriding the duration the theme provides. A reduced-motion preference still collapses it, unless the ForceAnimation parameter opts out of that. |
| UnmountOnCollapse | bool | false | Removes the content of the accordion from the DOM while it is collapsed, so that nothing it holds keeps running behind a closed header. The collapse of an accordion that unmounts its content is not animated, since there is nothing left to animate. |
BitAccordion public members
| Name | Type | Default value | Description |
|---|---|---|---|
| Expand | Task | Expands the accordion. Does nothing if it is already expanded, and reports the change through the IsExpanded binding, OnChange and OnExpand. | |
| Collapse | Task | Collapses the accordion. Does nothing if it is already collapsed, and reports the change through the IsExpanded binding, OnChange and OnCollapse. | |
| Toggle | Task | Expands the accordion if it is collapsed and collapses it if it is expanded, reporting the change through the IsExpanded binding, OnChange and OnExpand/OnCollapse. | |
| FocusAsync | ValueTask | Gives the focus to the header of the accordion, so that a panel the app has just opened is also where the keyboard is standing. The overload taking a bool prevents the header from being scrolled into view. |
BitComponentBase parameters
| Name | Type | Default value | Description |
|---|---|---|---|
| AriaLabel | string? | null | Gets or sets the accessible label for the component, used by assistive technologies. |
| Class | string? | null | Gets or sets the CSS class name(s) to apply to the rendered element. |
| Dir | BitDir? | null | Gets or sets the text directionality for the component's content. |
| ForceAnimation | bool | false | Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested. |
| HtmlAttributes | Dictionary<string, object> | new Dictionary<string, object>() | Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. |
| Id | string? | null | Gets or sets the unique identifier for the component's root element. |
| IsEnabled | bool | true | Gets or sets a value indicating whether the component is enabled and can respond to user interaction. |
| Style | string? | null | Gets or sets the CSS style string to apply to the rendered element. |
| TabIndex | string? | null | Gets or sets the tab order index for the component when navigating with the keyboard. |
| Visibility | BitVisibility | BitVisibility.Visible | Gets or sets the visibility state (visible, hidden, or collapsed) of the component. |
BitComponentBase public members
| Name | Type | Default value | Description |
|---|---|---|---|
| UniqueId | Guid | Guid.NewGuid() | Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed. |
| RootElement | ElementReference | Gets the reference to the root HTML element associated with this component. |
BitAccordionToggleArgs properties
| Name | Type | Default value | Description |
|---|---|---|---|
| IsExpanding | bool | The state the accordion is about to move to: true while it is expanding, false while it is collapsing. | |
| Reason | BitAccordionToggleReason | What made the accordion expand or collapse: a click on its header, or a call to one of its Expand, Collapse and Toggle methods. | |
| Cancel | bool | false | Set to true to cancel the expansion or the collapse and leave the accordion as it is. |
BitAccordionClassStyles properties
| Name | Type | Default value | Description |
|---|---|---|---|
| Root | string? | null | Custom CSS classes/styles for the root element of the BitAccordion. |
| Expanded | string? | null | Custom CSS classes/styles for the expanded state of the BitAccordion. |
| HeaderWrapper | string? | null | Custom CSS classes/styles for the header wrapper of the BitAccordion, which holds the heading and the actions. |
| Heading | string? | null | Custom CSS classes/styles for the heading element of the BitAccordion that wraps the header button. |
| Header | string? | null | Custom CSS classes/styles for the header of the BitAccordion. |
| Icon | string? | null | Custom CSS classes/styles for the icon at the start of the header of the BitAccordion. |
| HeaderContent | string? | null | Custom CSS classes/styles for the header content of the BitAccordion. |
| Title | string? | null | Custom CSS classes/styles for the title of the BitAccordion. |
| Description | string? | null | Custom CSS classes/styles for the description of the BitAccordion. |
| ExpanderIconWrapper | string? | null | Custom CSS classes/styles for the expander icon wrapper of the BitAccordion. |
| ExpanderIcon | string? | null | Custom CSS classes/styles for the expander icon of the BitAccordion. |
| ExpandedIcon | string? | null | Custom CSS classes/styles for the icon of the BitAccordion in expanded state. |
| Actions | string? | null | Custom CSS classes/styles for the actions of the BitAccordion, rendered beside the header. |
| ContentContainer | string? | null | Custom CSS classes/styles for the content container of the BitAccordion. |
| ContentWrapper | string? | null | Custom CSS classes/styles for the content wrapper of the BitAccordion, which clips the content while it collapses. |
| Content | string? | null | Custom CSS classes/styles for the content of the BitAccordion. |
BitColorKind enum
| Name | Value | Description |
|---|---|---|
| Primary | 0 | The primary color kind. |
| Secondary | 1 | The secondary color kind. |
| Tertiary | 2 | The tertiary color kind. |
| Transparent | 3 | The transparent color kind. |
BitIconPosition enum
| Name | Value | Description |
|---|---|---|
| Start | 0 | Icon renders before the content. |
| End | 1 | Icon renders after the content (default). |
BitAccordionToggleReason enum
| Name | Value | Description |
|---|---|---|
| Click | 0 | The header of the accordion was clicked, or activated by the Enter or the Space key. |
| Method | 1 | The Expand, Collapse or Toggle method of the accordion was called. |
BitSize enum
| Name | Value | Description |
|---|---|---|
| Small | 0 | The small size. |
| Medium | 1 | The medium size. |
| Large | 2 | The large size. |
BitVisibility enum
| Name | Value | Description |
|---|---|---|
| Visible | 0 | The content of the component is visible. |
| Hidden | 1 | The content of the component is hidden, but the space it takes on the page remains (visibility:hidden). |
| Collapsed | 2 | The component is hidden (display:none). |
BitDir enum
| Name | Value | Description |
|---|---|---|
| Ltr | 0 | Ltr (left to right) is to be used for languages that are written from the left to the right (like English). |
| Rtl | 1 | Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic). |
| Auto | 2 | Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element. |
Feedback
Found a mistake, a gap, or something that could be clearer? Every page and every component is one click from its source.