Skip to content

Collapsible

LayoutSince 0.9.0
import { Collapsible } from '@absoluteui/components/collapsible';
import '@absoluteui/components/collapsible/style.css';

Using Angular? See Collapsible for Angular.

A single disclosure: a native <button> with aria-expanded and aria-controls, optionally inside a heading, that shows and hides one content region, such as “Show more details” or an advanced-settings section. Accordion is for several related sections; Collapsible is for one.

  • Optional or advanced content that most users do not need: details, advanced settings, long explanations.
  • One section that the user can expand on its own.
  • Several related sections: use Accordion.
  • Content the user must see to complete the task (do not hide it).
  • Navigation menus: use Menu or Sidebar.
import { Collapsible } from '@absoluteui/components/collapsible';
const host = document.createElement('div');
document.body.append(host);
Collapsible.create(host, {
label: 'How is the delivery date calculated?',
content: 'Orders placed before 14:00 on a business day ship the same day. Weekends and public holidays are not counted.',
});
import { Collapsible, type CollapsibleChangeDetail } from '@absoluteui/components/collapsible';
import { Switch } from '@absoluteui/components/switch';
const host = document.createElement('section');
const settings = document.createElement('div');
const cacheHost = document.createElement('div');
settings.append(cacheHost);
document.body.append(host);
Switch.create(cacheHost, { label: 'Cache responses for offline use' });
Collapsible.create(host, { label: 'Advanced settings', content: settings, headingLevel: 3, variant: 'bordered' });
// Remember that the user has seen the advanced settings (aui-change fires only on user toggles).
host.addEventListener('aui-change', (event) => {
if ((event as CustomEvent<CollapsibleChangeDetail>).detail.open) host.dataset.viewed = 'true';
});
import { Collapsible } from '@absoluteui/components/collapsible';
import '@absoluteui/components/collapsible/style.css';
const host = document.querySelector<HTMLElement>('#more');
if (host) Collapsible.create(host, { label: 'Show more details', content: 'The report includes all closed tickets from the last quarter.' });
import { Collapsible } from '@absoluteui/components/collapsible';
const host = document.querySelector<HTMLElement>('#shipping-help');
const details = document.querySelector<HTMLTemplateElement>('#shipping-details');
if (host && details) {
Collapsible.create(host, { label: 'How is the delivery date calculated?', content: details.content.cloneNode(true) });
}
<div class="aui-collapsible aui-collapsible--{variant} [aui-collapsible--open]">
[<h3 class="aui-collapsible__heading">]
<button class="aui-collapsible__trigger" aria-expanded aria-controls="panel">
<span class="aui-collapsible__label">label</span>
icon (rotates when open)
</button>
[</h3>]
<div class="aui-collapsible__panel" id="panel" [hidden]>
<div class="aui-collapsible__clip"><div class="aui-collapsible__content">content</div></div>
</div>
</div>
Collapsible.create(host: HTMLElement, options: CollapsibleOptions): Collapsible

Global configuration key: collapsible (see Configuration).

Option Type Default Description
label string Trigger text. Required.
content Node | string Region content; strings are rendered as text. Required.
open boolean "false" Initial state; with update(), sets the state.
disabled boolean "false" Blocks toggling (aria-disabled; the trigger stays focusable).
headingLevel 2 | 3 | 4 | 5 | 6 | null Wrap the trigger in a heading of this level.
variant 'plain' | 'bordered' "plain" plain: text trigger; bordered: full-width trigger in a bordered surface. Globally configurable.
icons Partial<CollapsibleIcons> Icon slot overrides.
Property Type Description
host HTMLElement The host element.
open boolean Whether the content is shown.
trigger HTMLButtonElement The trigger button.
content HTMLDivElement The content container.
options Readonly<CollapsibleOptions> Current options.
Method Description
show(): void Show the content (no event).
hide(): void Hide the content (no event).
toggle(): void Toggle the content (no event).
update(options: Partial<CollapsibleOptions>): void Merge and apply options; open sets the state.
destroy(): void Remove rendering, classes, listeners, and subscriptions.
Event Detail Bubbles Cancelable Description
aui-change CollapsibleChangeDetail Yes No The user toggled the content: { open }.
Area Description
content Region content (Node or text).

All rules live in the aui.components cascade layer, so application styles override them without specificity battles.

Class Purpose
aui-collapsible Host.
aui-collapsible--plain | --bordered Variant modifiers.
aui-collapsible--open | --disabled State modifiers.
aui-collapsible__heading Heading around the trigger (optional).
aui-collapsible__trigger The disclosure button.
aui-collapsible__label Trigger text.
aui-collapsible__icon Expand icon (rotates when open).
aui-collapsible__panel The controlled region.
aui-collapsible__content Content container.
Slot Default icon
expand chevron-down

Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.

--aui-border-width | --aui-color-border | --aui-color-focus-ring | --aui-color-hover | --aui-color-link | --aui-color-surface | --aui-color-text | --aui-color-text-disabled | --aui-color-text-muted | --aui-duration-fast | --aui-duration-normal | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-weight-medium | --aui-icon-size-sm | --aui-line-height-normal | --aui-line-height-tight | --aui-radius-md | --aui-radius-sm | --aui-space-2 | --aui-space-4 | --aui-touch-target-min

type CollapsibleVariant = 'plain' | 'bordered';
type CollapsibleHeadingLevel = 2 | 3 | 4 | 5 | 6;
interface CollapsibleConfig { variant: CollapsibleVariant }
interface CollapsibleIcons { expand: IconRef }
interface CollapsibleOptions extends Partial<CollapsibleConfig> {
label: string;
content: Node | string;
open?: boolean;
disabled?: boolean;
headingLevel?: CollapsibleHeadingLevel | null;
icons?: Partial<CollapsibleIcons>;
}
interface CollapsibleChangeDetail { open: boolean }

Pattern: WAI-ARIA APG Disclosure: a button with aria-expanded and aria-controls shows and hides one content region.

Key Context Action
Enter / Space Trigger Show or hide the content.
Tab Any Moves to the trigger, then into the content when it is shown.
Element Role
trigger button (native)
heading heading (native h2-h6, optional)
panel none (a div controlled by the button)
Attribute Element Value
aria-expanded trigger true when open, false when closed
aria-controls trigger the panel id
aria-disabled trigger true when disabled (the trigger stays focusable)

Focus stays on the trigger when toggling; hidden content is out of the tab order.

Criterion Level Note
1.3.1 Info and Relationships A
2.1.1 Keyboard A
2.4.7 Focus Visible AA
4.1.2 Name, Role, Value A

Automated test results: Accessibility and compliance.

  • The icon rotation conveys the state visually; aria-expanded conveys it to assistive technology.
  • Height animation respects prefers-reduced-motion and the animation ‘none’ setting.
  • Manual screen-reader verification (NVDA, JAWS, VoiceOver) is pending.

Closed, open, disabled; plain or bordered; with or without a heading.

From Trigger To
closed click, Enter, or Space on the trigger open (aui-change with open: true)
open click, Enter, or Space on the trigger closed (aui-change with open: false)
any show(), hide(), toggle(), update({ open }) the requested state, no event
any (disabled) activation unchanged
  • Keep the label the same whether open or closed; aria-expanded announces the state.
  • Do not hide content the user needs to finish the task.
  • The e2e axe run covers three themes; manual screen-reader verification is pending.

Full width of its container. The region height animates when motion is allowed.

Logical properties: the icon follows the label at the inline end.

Plain triggers turn color-link on hover; bordered triggers use color-hover. The focus ring uses color-focus-ring. Animation is off with prefers-reduced-motion and the animation setting none. Forced-colors mode uses CanvasText borders and GrayText for a disabled trigger.

configureAbsoluteUI({ components: { collapsible: { variant: 'bordered' } } });

The instance variant overrides configuration; configuration changes re-render existing instances.

icons.expand (default chevron-down); it rotates 180 degrees when open.

The label and string content are rendered as text, never parsed as HTML. Node content is inserted as given; the application owns it.

No persistence, network access, or telemetry.

Constant work per toggle: attribute and class updates. Content is built once and kept while hidden.

Not data-driven.

  • Content open at creation does not animate on load; the animation starts with the first toggle.
  • Changing headingLevel moves the same trigger into the new heading, so focus is kept.
  • Hidden content is not found by the browser’s find in page.
Code Category Cause
COLLAPSIBLE_OPTIONS configuration Missing or blank label, missing content, a non-boolean open or disabled, or an invalid heading level.
ICON_UNKNOWN configuration Unknown icon override.
CFG_INVALID_VALUE / CFG_UNKNOWN_OPTION configuration Invalid variant or unknown configuration.

Invalid options throw before the host is modified; an invalid update() leaves the previous state intact.

  • The open state is not remembered across page loads.
  • Manual screen-reader verification is pending.
  • Several sections with single-open behavior: use Accordion.
  • HTML strings as content: pass a Node.