content-swap
Two-face content toggle with flip, fade, slide, and scale transitions. Theme-driven motion via design tokens.
Overview
The <content-swap> component toggles between two content faces with configurable transition effects. It manages inert on the hidden face so screen readers only announce visible content.
The transition type is a styling concern (data-transition), while duration and easing come from VB motion tokens — so themes automatically control the personality of every swap.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-transition |
string | flip |
Transition effect: flip, flip-vertical, fade, slide-left, slide-up, scale. |
data-swapped |
boolean | false |
Reflects the current swap state. Can be set to start swapped. |
data-card |
boolean | — | Applies layout-card visual shell (background, radius, shadow). |
data-variant |
string | — | Card variant when using data-card: elevated, outlined, ghost. |
Child Attributes
| Attribute | Where | Description |
|---|---|---|
data-face="front" |
Direct child | Marks the front face. |
data-face="back" |
Direct child | Marks the back face. |
data-swap |
Any descendant | Marks an element as a swap trigger button. |
Transition Effects
Each transition reads from VB motion tokens, so themes automatically control personality.
| Value | Animation | Kawaii | Brutalist |
|---|---|---|---|
flip |
3D rotateY | Bouncy easing, 300ms | Instant cut |
flip-vertical |
3D rotateX | Bouncy easing | Instant cut |
fade |
Crossfade opacity | 300ms fade | Hard opacity toggle |
slide-left |
Horizontal slide | Slide with bounce | Hard slide, linear |
slide-up |
Vertical slide | Slide with bounce | Hard slide, linear |
scale |
Scale + opacity | Pop with bounce | Linear scale |
Fade
Click to swapFaded in
Slide Left
Click to swapSlid in
Scale
Click to swapScaled in
Trigger Buttons
By default, clicking anywhere on the element triggers the swap. Add data-swap to specific buttons for explicit trigger controls. When triggers exist, the container is no longer clickable.
Question: What does inert do?
Answer: It makes an element and its descendants non-interactive and hidden from assistive technology.
Card Mode
Add data-card to apply layout-card's visual shell directly on the swap element. Supports data-variant for elevated, outlined, and ghost styles.
Product
Flip to see details.
Details
Price, specs, and more.
Outlined
Card mode with outlined variant.
Back
Still outlined.
Page-level auto-card
Add data-swap-autocard to a container or <body> to automatically apply card chrome to all content-swap elements that don't already wrap <layout-card> children.
Composition
Wrap <layout-card> elements as faces for full card structure (header, section, footer) on each side.
Front Card
Full card structure with header, section, and footer.
Back Card
Each face is an independent layout-card.
Attribute Form
For authors who want swap behavior on an existing element, add data-swap as an attribute on any element with data-face children. The behavior auto-initializes via JavaScript.
Keyboard Navigation
| Key | Action |
|---|---|
| Enter / Space | Toggle swap (when element or trigger is focused) |
| Tab | Move focus to next interactive element |
Events
| Event | Detail | Description |
|---|---|---|
content-swap |
{ swapped: boolean } |
Fired after the content swaps. |
JavaScript API
| Method / Property | Description |
|---|---|
flip() |
Swap to show the back face. |
unflip() |
Swap to show the front face. |
toggle() |
Toggle between front and back. |
swapped |
Boolean property reflecting the current state. |
flipped |
Alias for swapped (backward compatibility). |
Theme Integration
Content-swap reads from VB motion tokens. Themes override these tokens, so personality comes for free:
- Default:
--motion-enter-duration: 300ms,--ease-default: var(--ease-3) - Kawaii: Bouncy easing (
cubic-bezier(0.34, 1.56, 0.64, 1)), 300ms - Brutalist: Linear easing, 0ms (instant cut)
No extra theme CSS needed — the token bridge handles it.
Accessibility
Inert Toggling
The hidden face is always marked inert. Screen readers only announce the currently visible face, and interactive elements on the hidden face cannot receive focus.
Trigger Modes
- Whole-element trigger (no
data-swapchildren): The element getsrole="button",tabindex="0", andaria-label="Toggle content". - Explicit triggers (
data-swapchildren): The trigger buttons are the keyboard targets. No role is added to the container.
Focus Management
When swapping, focus moves to the first interactive element on the newly visible face (buttons, links, inputs, or elements with autofocus).
Reduced Motion
When prefers-reduced-motion: reduce is active, the swap animation duration is set to 0s. The state still toggles instantly without animation.
Progressive Enhancement
Without JavaScript, both faces display stacked in natural document flow. The :not(:defined) selector ensures transforms only apply once the component is registered.
Related Elements
<layout-card>— Card visual shell (compose with content-swap)<accordion-wc>— Collapsible content panels<tabs-wc>— Tab panels for content switching