Collapsible
stimeo--collapsible
A single disclosure region that expands and collapses in place.
The stimeo--collapsible controller implements the WAI-ARIA Disclosure pattern for one trigger/content pair. It keeps the trigger's aria-expanded in sync with the content's hidden attribute and data-state, and exposes the content's natural height as --stimeo-collapsible-content-height so the consumer's CSS can animate the height transition. The open lifecycle is ordered so hidden never blocks measurement, and hidden is re-applied after the close transition (or immediately when there is none). Behavior only — styling is owned by this Playground.
Orders placed before 2pm ship the same business day. Standard delivery takes 3–5 business days; express options are shown at checkout.
Keyboard
| Key | Action |
|---|---|
| Enter / Space | Toggle the region open or closed (native button). |
<%# Markup for the collapsible (APG Disclosure) demo.
The trigger opens/closes a single region inline. The library syncs aria-expanded /
hidden / data-state and the content's measured-height variable; the look (the
height transition) lives in demo.css. %>
<div class="collapsible" data-controller="stimeo--collapsible">
<button
class="collapsible__trigger"
type="button"
aria-expanded="false"
aria-controls="collapsible-demo-content"
data-stimeo--collapsible-target="trigger"
data-action="click->stimeo--collapsible#toggle">
<span class="collapsible__chevron" aria-hidden="true"></span>
<%= t("components.collapsible.demo.trigger") %>
</button>
<div
class="collapsible__content"
id="collapsible-demo-content"
data-state="closed"
hidden
data-stimeo--collapsible-target="content">
<p class="collapsible__body"><%= t("components.collapsible.demo.body") %></p>
</div>
</div>
/*
* Presentation-only styles for the collapsible demo.
* The open/close animation uses the data-state the library sets on the content
* target and --stimeo-collapsible-content-height (the content's measured height).
*/
.collapsible {
max-width: 32rem;
border: 1px solid var(--border-default);
border-radius: 0.5rem;
overflow: hidden;
}
.collapsible__trigger {
display: flex;
align-items: center;
gap: 0.5rem;
width: 100%;
padding: 0.75rem 1rem;
background: var(--surface-subtle);
border: 0;
font: inherit;
font-weight: 600;
color: var(--fg);
cursor: pointer;
text-align: left;
}
.collapsible__chevron {
width: 0.5rem;
height: 0.5rem;
border-right: 2px solid currentColor;
border-bottom: 2px solid currentColor;
transform: rotate(-45deg);
transition: transform 0.2s ease;
}
.collapsible__trigger[aria-expanded="true"] .collapsible__chevron {
transform: rotate(45deg);
}
/* Transition the height while opening/closing or open (i.e. once hidden is removed). */
.collapsible__content {
height: 0;
overflow: hidden;
transition: height 0.2s ease;
}
.collapsible__content[data-state="open"] {
height: var(--stimeo-collapsible-content-height);
}
.collapsible__body {
margin: 0;
padding: 1rem;
}
/* Disable the transition under reduced motion (fall back to instant open/close). */
@media (prefers-reduced-motion: reduce) {
.collapsible__content,
.collapsible__chevron {
transition: none;
}
}
This demo needs no consumer-side JS (the controller handles the behavior).
These demo styles use shared design tokens (light + dark). Copy the shared styles too, then toggle data-theme on your root element for dark mode.
The data-* attributes you add to your own HTML to wire this component. Put the data-controller below on a root element, then place its targets / values / actions inside that element.
On the root element
data-controller="stimeo--collapsible"
Targets
| Name | Description | Attribute |
|---|---|---|
trigger
required
|
The button that toggles the single disclosure region; carries aria-expanded. |
data-stimeo--collapsible-target="trigger" |
content
required
|
The inline region that expands/collapses; its data-state, hidden, and height variable are driven by the controller. |
data-stimeo--collapsible-target="content" |
Values
| Name | Description | Attribute |
|---|---|---|
open
|
Initial open state reflected onto the DOM on connect without animating (default false). | data-stimeo--collapsible-open-value |
Actions
| Name | Description | Action |
|---|---|---|
toggle
|
Toggles the region open/closed (animated), ordering hidden/data-state/height so the transition can run. |
stimeo--collapsible#toggle |
State hooks
The library only manages these ARIA/data attributes and custom properties. Your CSS reads them to render the look — selectors like [aria-selected], [aria-expanded], or var(--stimeo--…) hook into this state.
| Hook | Target | Meaning |
|---|---|---|
aria-expanded |
Trigger | "true" when open, "false" when closed. |
hidden |
Content | Present when closed (added after the close transition). |
data-state |
Content | "open" / "closed" — the height-animation starting point. |
--stimeo-collapsible-content-height |
Content | The content's measured height (px) for the height transition. |