General
Collapsible
Usage#
import { WDS_COLLAPSIBLE } from '@wds/angular/collapsible';Examples#
Default#
wds-collapsible, for example the trigger in a header. They belong to the nearest wds-collapsible, so panels can be nested.
@peduarte starred 3 repositories
import { Component } from '@angular/core';
import { WdsCollapsibleComponent, WdsCollapsibleContentComponent, WdsCollapsibleTriggerComponent } from '@wds/angular/collapsible';
import { WdsButtonComponent } from '@wds/angular/button';
@Component({
selector: 'app-collapsible-default-demo',
imports: [WdsCollapsibleComponent, WdsCollapsibleTriggerComponent, WdsCollapsibleContentComponent, WdsButtonComponent],
template: `
<wds-collapsible class="flex w-[350px] flex-col gap-2">
<div class="flex items-center justify-between gap-4 px-4">
<h4 class="m-0 text-sm font-semibold">@peduarte starred 3 repositories</h4>
<wds-collapsible-trigger>
<wds-button variant="ghost" size="icon-sm" label="Toggle">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 15 5 5 5-5" /><path d="m7 9 5-5 5 5" /></svg>
</wds-button>
</wds-collapsible-trigger>
</div>
<div class="rounded-md border border-border px-4 py-2 font-mono text-sm">@radix-ui/primitives</div>
<wds-collapsible-content>
<div class="flex flex-col gap-2">
<div class="rounded-md border border-border px-4 py-2 font-mono text-sm">@radix-ui/colors</div>
<div class="rounded-md border border-border px-4 py-2 font-mono text-sm">@stitches/react</div>
</div>
</wds-collapsible-content>
</wds-collapsible>
`,
})
export class CollapsibleDefaultDemo {}Disabled#
disabled disables the trigger; the panel keeps its current state.
import { Component } from '@angular/core';
import { WdsCollapsibleComponent, WdsCollapsibleContentComponent, WdsCollapsibleTriggerComponent } from '@wds/angular/collapsible';
import { WdsButtonComponent } from '@wds/angular/button';
@Component({
selector: 'app-collapsible-disabled-demo',
imports: [WdsCollapsibleComponent, WdsCollapsibleTriggerComponent, WdsCollapsibleContentComponent, WdsButtonComponent],
template: `
<wds-collapsible class="flex w-[350px] flex-col gap-2" disabled open>
<wds-collapsible-trigger>
<wds-button variant="outline" size="sm">Can't toggle</wds-button>
</wds-collapsible-trigger>
<wds-collapsible-content>
<div class="rounded-md border border-border px-4 py-3 text-sm text-muted-foreground">
The trigger is disabled, so the panel stays exactly as it was rendered.
</div>
</wds-collapsible-content>
</wds-collapsible>
`,
})
export class CollapsibleDisabledDemo {}Controlled#
open sets it, wds-open-change reports a change made with the trigger. Setting open from code does not fire the event.
import { Component, signal } from '@angular/core';
import { WdsButtonComponent } from '@wds/angular/button';
import { WDS_COLLAPSIBLE } from '@wds/angular/collapsible';
@Component({
selector: 'app-collapsible-controlled-demo',
imports: [...WDS_COLLAPSIBLE, WdsButtonComponent],
template: `
<div class="flex w-[350px] flex-col gap-3">
<div class="flex items-center justify-between gap-4">
<span class="text-sm text-muted-foreground">The panel is {{ open() ? 'open' : 'closed' }}</span>
<wds-button variant="outline" size="sm" (click)="open.set(!open())">{{ open() ? 'Close' : 'Open' }} from outside</wds-button>
</div>
<wds-collapsible class="flex flex-col gap-2" [open]="open()" (wdsOpenChange)="open.set($event.open)">
<wds-collapsible-trigger>
<wds-button variant="secondary" size="sm">Toggle from inside</wds-button>
</wds-collapsible-trigger>
<wds-collapsible-content>
<div class="rounded-md border border-border px-4 py-3 text-sm text-muted-foreground">
Both buttons change the same state, so the panel always matches the app.
</div>
</wds-collapsible-content>
</wds-collapsible>
</div>
`,
})
export class CollapsibleControlledDemo {
protected readonly open = signal(true);
}API References#
wds-collapsible#
wds-collapsible holds the state, a click on wds-collapsible-trigger toggles it,
and wds-collapsible-content expands smoothly. Both parts can be nested at any depth
(e.g. the trigger in a header); they belong to the nearest wds-collapsible, so panels can be nested.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
| open | boolean | false | wds-open-change. |
| disabled | boolean | false |
Events
| Event | Description |
|---|---|
| wds-open-changeCustomEvent<WdsCollapsibleOpenChangeDetail> | toggle() opened or closed the panel. |
Methods
| Method | Description |
|---|---|
| toggle() | disabled. |
Slots
| Slot | Description |
|---|---|
| (default) |
wds-collapsible-trigger#
wds-collapsible. It has no look of its own
(display: contents). The first element inside (e.g. wds-button or button) gets
aria-expanded, aria-controls and disabled, and the trigger itself data-state="open|closed".
Slots
| Slot | Description |
|---|---|
| (default) |
wds-collapsible-content#
wds-collapsible. It expands smoothly (height through grid-template-rows),
and when closed it is visibility: hidden, so it also leaves the tab sequence and the accessibility tree.
The state is in data-state="open|closed".
Slots
| Slot | Description |
|---|---|
| (default) |
CSS parts (::part)
| Part | Description |
|---|---|
| content |
CSS custom properties
| Property | Description |
|---|---|
| --wds-collapsible-duration |
Accessibility#
Screen reader#
wds-collapsible-trigger has no role of its own: the first element inside it (wds-button or <button>) is the button. It gets aria-expanded with the current state and aria-controls pointing to the content.
wds-collapsible-content has visibility: hidden, so its content is hidden from screen readers and from the tab sequence.
disabled the trigger button is disabled. Give an icon-only trigger button a label.
Keyboard support#
| Key | Function |
|---|---|