layout-switcher

A flexbox container that automatically switches from horizontal to vertical layout based on available space. Ideal for responsive layouts without media queries.

Attributes

Attribute Values Default Description
data-layout-threshold 20rem, 25rem, 30rem, 35rem, 40rem, 45rem 30rem Container width at which layout switches from horizontal to vertical
data-layout-gap none, xs, s, m, l, xl m Gap between items
data-layout-limit 2, 3, 4 - Maximum items before forcing vertical layout
data-layout-reverse boolean - Reverses order when stacked

Basic Usage

Items display side-by-side when space allows, then stack vertically.

Item 1

Content that shares space horizontally when there's room.

Item 2

Stacks vertically when the container is narrow.

Code

<layout-switcher data-layout-gap="m"> <div>Item 1</div> <div>Item 2</div> </layout-switcher>

Threshold Variants

The data-layout-threshold attribute controls when the switch happens.

Lower Threshold (20rem)

Stays horizontal longer, only stacks on very narrow containers.

Card A

Card B

Higher Threshold (40rem)

Switches to vertical layout earlier, at wider container widths.

Card A

Card B

Code

<!-- Lower threshold - stays horizontal longer --> <layout-switcher data-layout-threshold="20rem"> <div>Card A</div> <div>Card B</div> </layout-switcher> <!-- Higher threshold - stacks earlier --> <layout-switcher data-layout-threshold="40rem"> <div>Card A</div> <div>Card B</div> </layout-switcher>

Item Limit

The data-layout-limit attribute forces vertical layout when there are more items than the limit.

Limit of 2

Item 1

Item 2

Item 3 (forces stack)

Code

<!-- Forces vertical when more than 2 items --> <layout-switcher data-layout-gap="m" data-layout-limit="2"> <div>Item 1</div> <div>Item 2</div> <div>Item 3</div> <!-- This causes stack --> </layout-switcher>

Usage Examples

Form Actions

<layout-switcher data-layout-gap="s" data-layout-threshold="25rem"> <button type="button" class="secondary">Cancel</button> <button type="submit">Save Changes</button> </layout-switcher>

Card Header

Project Name

Last updated 2 hours ago

<layout-card data-variant="outlined" data-padding="m"> <layout-switcher data-layout-gap="m" data-layout-threshold="30rem"> <layout-stack data-layout-gap="xs"> <strong>Project Name</strong> <p>Last updated 2 hours ago</p> </layout-stack> <layout-cluster data-layout-gap="s"> <button type="button" class="small secondary">Edit</button> <button type="button" class="small">View</button> </layout-cluster> </layout-switcher> </layout-card>

Feature Comparison

Basic

$9/mo

  • 5 Projects
  • 10GB Storage
  • Email Support
Pro

$29/mo

  • Unlimited Projects
  • 100GB Storage
  • Priority Support
<layout-switcher data-layout-gap="l" data-layout-threshold="35rem"> <layout-card data-variant="outlined" data-padding="l"> <layout-stack data-layout-gap="m" data-layout-align="center"> <strong>Basic</strong> <span>$9/mo</span> <button type="button" class="secondary">Choose Basic</button> </layout-stack> </layout-card> <layout-card data-variant="elevated" data-padding="l"> <layout-stack data-layout-gap="m" data-layout-align="center"> <strong>Pro</strong> <span>$29/mo</span> <button type="button">Choose Pro</button> </layout-stack> </layout-card> </layout-switcher>

CSS Implementation

layout-switcher { display: flex; flex-wrap: wrap; gap: var(--_gap, var(--size-m)); } layout-switcher > * { flex-grow: 1; flex-basis: calc((var(--_threshold, 30rem) - 100%) * 999); } /* Threshold variants */ layout-switcher[data-layout-threshold="20rem"] { --_threshold: 20rem; } layout-switcher[data-layout-threshold="30rem"] { --_threshold: 30rem; } layout-switcher[data-layout-threshold="40rem"] { --_threshold: 40rem; } /* Limit variants */ layout-switcher[data-layout-limit="2"] > :nth-last-child(n+3), layout-switcher[data-layout-limit="2"] > :nth-last-child(n+3) ~ * { flex-basis: 100%; }

Related Elements