Markup
Drop-in HTML structure. A button triggers the collapsible panel — all ARIA wiring is automatic.
<collapsible-component>
<button type="button">Section Title</button>
<collapsible-content>
<div class="content-wrapper">
<p>Your content here...</p>
</div>
</collapsible-content>
</collapsible-component>
<!-- Start open with the open attribute -->
<collapsible-content open>...</collapsible-content>
<!-- Custom animation speed (px/sec) -->
<collapsible-content speed="800">...</collapsible-content>
Accordion
Animation duration is calculated dynamically from content height using a
speed attribute (default: 900 px/sec). Short panels
animate quickly, tall panels take proportionally longer — no fixed duration
that feels too slow or too fast.
The native <details> element snaps open instantly with no
animation. This component provides smooth height transitions, proper ARIA
attributes, inert management for hidden content, and programmatic control via
the .collapsed property.
Yes. The component automatically manages
aria-expanded on the button, aria-hidden and
inert on the content panel, and links the two with
aria-controls and aria-labelledby. Focus is trapped
out of collapsed content.
Absolutely. Each
<collapsible-component> operates independently. Nest them as
deeply as you need — the height animation recalculates correctly for all
levels.
There's no Shadow DOM, so you style everything with plain CSS. Customize
animation timing with
--collapsible-duration and --collapsible-easing. Style
buttons, content, and layout with any selectors you like.
Accordion Group
Add a group attribute to <collapsible-component>
to create accordion behavior — opening one item automatically closes others
in the same group.
The group attribute links collapsible components
together. When one opens, all others in the same group close
automatically — classic accordion behavior.
Yes. Clicking the open item closes it without forcing another open. All items in a group can be collapsed at the same time.
The closing and opening animations run simultaneously. Try clicking between items — even mid-animation, everything stays smooth.
<collapsible-component group="faq">
<button type="button">Question One</button>
<collapsible-content>...</collapsible-content>
</collapsible-component>
<collapsible-component group="faq">
<button type="button">Question Two</button>
<collapsible-content>...</collapsible-content>
</collapsible-component>
Initially Open
Add the open attribute to <collapsible-content> to start
expanded.
Include the CSS and JS, then drop the markup into your page. The component registers itself automatically — no initialization code required. This section starts open by default.
Control state programmatically with the
.collapsed setter. Read the current state with the
.collapsed getter. Listen for the
collapsible-error event if child elements are missing.
Custom Easing
Override --collapsible-easing for different animation feels.
A longer duration with a spring overshoot curve. Great for playful interfaces where motion adds personality.
A lower min-duration of 150ms lets short panels snap open
faster than the default 250ms clamp. Paired with ease-out for a crisp feel.
The built-in default. A balanced ease curve that works well for most use cases.
A slow spring on a tall panel really shows off the animation curve. Watch the overshoot as it settles into place.
The spring easing overshoots its target height briefly before easing back — the taller the content, the more dramatic the effect. This is useful for reveal moments where you want the user to notice the motion.
-
Easing:
cubic-bezier(0.34, 1.56, 0.64, 1) - Content height drives the visual impact
- Works well for onboarding flows, feature tours, and settings panels
Pair a longer duration with generous content to create an intentional, cinematic feel. For shorter content, consider dialing the duration back to avoid the animation feeling sluggish.
Dynamic Speed
The speed attribute sets animation speed in px/sec. Duration scales with
content height so short and tall panels feel proportional. Default is 900.
A short paragraph. The animation is quick because there's less distance to cover.
This panel has a lot more content, so the animation takes proportionally longer. The speed stays consistent — only the duration changes.
- Duration scales linearly with content height
- Short panels feel snappy
- Tall panels feel smooth, not sluggish
- Mid-animation reversals stay proportional
- Duration is clamped between 250ms and 1s
Try clicking the button rapidly to see mid-animation reversal. The component captures the current in-progress height and calculates a new duration for the remaining distance.
The clamping ensures that very short panels don't animate so fast they feel instant, and very tall panels don't drag on forever. This creates a consistent feel regardless of content size.
- Minimum duration: 250ms — keeps short panels visible during transition
- Maximum duration: 1s — prevents tall panels from feeling sluggish
- Everything in between scales linearly with height
With min-duration="0.15", the minimum clamp drops to 150ms
so short panels animate faster. The ease-out curve gives a crisp, snappy
feel.
With speed="80", the animation moves at 80px/sec. Useful for
dramatic reveals or onboarding flows.
<collapsible-content>
<!-- default: 900px/sec -->
</collapsible-content> <collapsible-content
speed="1200">
<!-- faster: 1200px/sec -->
</collapsible-content> <collapsible-content
speed="80">
<!-- slower: 80px/sec -->
</collapsible-content>
Rich Content
Collapsible panels handle any content — lists, code, nested elements. Height recalculates automatically.
Package Manager
Install via npm and import into your build:
-
npm i @magic-spells/collapsible-content - Import the module and CSS in your entry file
- The component self-registers on import
Available Properties
-
--collapsible-duration— animation length (dynamic, based on content height) -
--collapsible-easing— timing function (default:ease-out)
Set these on the
<collapsible-content> element or any ancestor. The component
also respects prefers-reduced-motion — transitions are
disabled automatically when the user prefers reduced motion.
Components can be nested. Each instance operates independently:
This is a nested collapsible. The parent panel's height adjusts automatically when inner panels open or close.
Try opening both inner sections while the parent is open. The animation stays smooth at every level.
Keyboard & Accessibility
Full keyboard support and ARIA attributes are managed automatically.
aria-expanded
Set on button
aria-controls
Links button to panel
aria-labelledby
Labels panel by button
aria-hidden
Hides collapsed content
inert
Prevents focus in hidden panels
focus-visible
Keyboard-only outline