Overview
Single-panel show/hide disclosure — the single-item counterpart to Accordion. A labeled trigger toggles one region, animating its height open and closed with Svelte's native slide transition.
Usage
Uncontrolled — the component owns its state:
Controlled — the parent owns the state with bind:open:
State model
open is bindable. Without bind:open, it seeds local state and can still be updated by parent prop changes, but trigger clicks update local state only. Use bind:open (or mirror onToggle in the parent) when parent and trigger interactions must stay fully synchronized. onToggle fires on every toggle with the next boolean, so one-way observers stay in sync.
The trigger prop is either a string or a snippet receiving { open, disabled }, letting the label react to state (for example, swapping "Show" and "Hide").
Use triggerAriaLabel when you need a dedicated accessible name on the internal trigger button. It accepts either a static string or a state-aware function (({ open, disabled }) => string) for dynamic labels and stable getByRole(..., { name }) selectors.
Accessibility
- The trigger is a native
<button type="button">, so Enter and Space activation and tab order come from the browser.disableduses the real attribute, removing it from the tab order. - The trigger carries
aria-expanded; the panel is arole="region"labeled by the trigger viaaria-labelledby. - The panel is removed from the DOM when closed (standard disclosure behavior).
aria-controlsis emitted only while the panel exists, so it never references a missing element. Each open panel registers as a namedregionlandmark — on a page with many open Collapsibles, weigh that against landmark-navigation noise. - Height animation collapses to zero duration under
prefers-reduced-motion: reduce, and the chevron rotation transition is disabled in CSS.
For multiple coordinated sections where opening one may close others, use Accordion instead. See collapsible.a11y.md for a detailed comparison of when to use each pattern.
When to use
- Hiding a single optional region behind a labeled trigger.
- You need controlled or uncontrolled show/hide with an accessible toggle.
- Coordinating multiple sections where opening one may close others — use accordion.
Examples
Uncontrolled disclosure
Without bind:open the component owns its toggle state.
Controlled with bind:open
An external control drives open state via two-way binding.
Disabled trigger
A disabled Collapsible cannot be toggled. The native disabled attribute removes the trigger from the tab order.
State-aware trigger label
A snippet trigger receives { open, disabled } so the label can react to state.
Props
| Name | Type | Default | Required | Bindable | Description |
|---|---|---|---|---|---|
trigger | stringSnippet<[CollapsibleTriggerState]> | req | Trigger label: a plain string, or a snippet receiving { open, disabled }. | ||
children | snippet | req | Panel content shown when open. | ||
open | boolean | false | bind | Bindable open state. Without bind:open, this seeds local state and can be
updated by parent prop changes, while trigger clicks update local state.
Use bind:open for full parent/trigger synchronization. | |
onToggle | (open: boolean) => void | Fired on every successful toggle with the next open state. Not called while disabled. | |||
disabled | boolean | false | When true, the trigger cannot be toggled. | ||
triggerAriaLabel | string((state: CollapsibleTriggerState) => string) | Accessible name override for the internal trigger button. Accepts either a
fixed string or a function receiving { open, disabled } so labels can
react without requiring bind:open. | |||
idBase | text | Base used to derive the trigger and panel ARIA ids (<base>-header,
<base>-label, <base>-panel). NOT the root element id. Auto-generated
when omitted. |