API
Display
The --display utility and the keywords the kit adds to it: flex directions, the pile, the gallery, and subgrids.
--display writes the CSS display property, so it takes whatever display takes: block, flex, grid, none, contents. The kit adds thirteen keywords of its own. Each sets a display and the thing you would otherwise set right after it: a flex direction, a shared cell, or a set of grid tracks.
| Keyword | What you get |
|---|---|
flex-row, flex-col | a flex container and its direction |
flex-row-reverse, flex-col-reverse | the same, laid out from the far end |
inline-flex-row, inline-flex-col, and their -reverse forms | an inline flex container and its direction |
grid-pile | a grid with every direct child in one cell, centered |
grid-gallery | a grid that picks its column count from its child count |
subgrid | a grid on its parent grid's columns and rows |
subgrid-col | a grid on its parent grid's columns |
subgrid-row | a grid on its parent grid's rows |
Breakpoints and spelling
--display takes breakpoints and no states. A tier needs a base, so write --display: none; --display--md: flex to hide something below md; --display--md: flex alone does nothing. Every keyword works at every breakpoint: --display: flex-col; --display--md: grid-gallery is a stack on a phone and a gallery from md up.
The kit matches the keywords as text, so they need exactly one space after the colon. --display:flex-col is not a flex container. The editor and <ui-debug> flag it.
Flex direction
The direction is part of the display, and there is no --flex-direction utility. A plain flex or inline-flex at a breakpoint goes back to a row.
<div
style="
--display: flex-col;
--gap: 11;
--w: 100%;
--max-w: 96;
"
>
<div
style="
--display: flex-col;
--gap: 2;
"
>
<span
data-ui="text-xs"
style="
--font-weight: strong;
--text: var(--color-muted-foreground);
"
>--display: flex-row</span
>
<div
style="
--display: flex-row;
--gap: 4;
"
>
<div
data-ui="text-sm"
style="
--flex: 1;
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
1
</div>
<div
data-ui="text-sm"
style="
--flex: 1;
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
2
</div>
<div
data-ui="text-sm"
style="
--flex: 1;
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
3
</div>
</div>
</div>
<div
style="
--display: flex-col;
--gap: 2;
"
>
<span
data-ui="text-xs"
style="
--font-weight: strong;
--text: var(--color-muted-foreground);
"
>--display: flex-col</span
>
<div
style="
--display: flex-col;
--gap: 4;
"
>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
1
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
2
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
3
</div>
</div>
</div>
</div>The -reverse forms lay the children out from the far end. Only the picture changes. A screen reader and the Tab key still follow the order in the markup, so don't reverse anything a person has to move through in sequence.
<div
style="
--display: flex-col;
--gap: 11;
--w: 100%;
--max-w: 96;
"
>
<div
style="
--display: flex-col;
--gap: 2;
"
>
<span
data-ui="text-xs"
style="
--font-weight: strong;
--text: var(--color-muted-foreground);
"
>
--display: flex-row-reverse
</span>
<div
style="
--display: flex-row-reverse;
--gap: 4;
"
>
<div
data-ui="text-sm"
style="
--flex: 1;
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
1
</div>
<div
data-ui="text-sm"
style="
--flex: 1;
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
2
</div>
<div
data-ui="text-sm"
style="
--flex: 1;
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
3
</div>
</div>
</div>
<div
style="
--display: flex-col;
--gap: 2;
"
>
<span
data-ui="text-xs"
style="
--font-weight: strong;
--text: var(--color-muted-foreground);
"
>
--display: flex-col-reverse
</span>
<div
style="
--display: flex-col-reverse;
--gap: 4;
"
>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
1
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
2
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
3
</div>
</div>
</div>
</div>The inline-flex- forms sit in a line of text, the way inline-flex does.
An inline-flex-row box sits in the line
one
two
and the sentence carries on.
An inline-flex-col box stacks its children
one
two
and the sentence carries on.
<div
style="
--display: flex-col;
--gap: 6;
--w: 100%;
--max-w: 96;
"
>
<p data-ui="text-sm" style="--m: 0">
An <code>inline-flex-row</code> box sits in the line
<span
style="
--display: inline-flex-row;
--px: 2;
--py: 1;
--gap: 1;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
<b>one</b>
<b>two</b>
</span>
and the sentence carries on.
</p>
<p data-ui="text-sm" style="--m: 0">
An <code>inline-flex-col</code> box stacks its children
<span
style="
--display: inline-flex-col;
--px: 2;
--py: 1;
--gap: 1;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
<b>one</b>
<b>two</b>
</span>
and the sentence carries on.
</p>
</div>For wrapping, growing, and alignment, see flexbox and grid.
Pile
--display: grid-pile puts every direct child in the same grid cell and centers it. It does what position: absolute layering does, except that the children stay in flow and the tallest one sets the height.
<div
style="
--display: grid-pile;
--w: 100%;
--h: 6;
--max-w: 96;
"
>
<div
style="
--size: 100%;
--bg: var(--color-muted);
--radius: 4.5;
"
></div>
<span data-ui="badge" data-badge-variant="primary">grid-pile</span>
<span
data-ui="badge"
data-badge-variant="muted"
style="
--self: start;
--mt: 4;
--ml: auto;
--mr: 4;
"
>stacked layer</span
>
</div>The centering beats a primitive's own alignment. A child's own placement wins over it, and so do --place-items and --items on the pile. On a layered hero, add --isolation: isolate so the layers' --z values stay inside it.
Gallery
--display: grid-gallery works out its own column count. It puts as many children in a row as fit, up to six, and it won't pick a count that leaves one child alone in the last row. Six children go 6, then 4 + 2, then 3 + 3 as the space narrows. They never go 5 + 1.
<div
style="
--display: flex-col;
--gap: 11;
--w: 100%;
--max-w: 160;
"
>
<div
style="
--display: flex-col;
--gap: 2;
"
>
<span
data-ui="text-xs"
style="
--font-weight: strong;
--text: var(--color-muted-foreground);
"
>
4 children: one row of four, or 2 + 2
</span>
<div
style="
--display: grid-gallery;
--gap: 2;
--ui-gallery-min-w: 5rem;
"
>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
1
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
2
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
3
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
4
</div>
</div>
</div>
<div
style="
--display: flex-col;
--gap: 2;
"
>
<span
data-ui="text-xs"
style="
--font-weight: strong;
--text: var(--color-muted-foreground);
"
>
5 children: one row of five, or 3 + 2
</span>
<div
style="
--display: grid-gallery;
--gap: 2;
--ui-gallery-min-w: 5rem;
"
>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
1
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
2
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
3
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
4
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
5
</div>
</div>
</div>
<div
style="
--display: flex-col;
--gap: 2;
"
>
<span
data-ui="text-xs"
style="
--font-weight: strong;
--text: var(--color-muted-foreground);
"
>
7 children: 5 + 2, or 4 + 3
</span>
<div
style="
--display: grid-gallery;
--gap: 2;
--ui-gallery-min-w: 5rem;
"
>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
1
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
2
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
3
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
4
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
5
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
6
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
7
</div>
</div>
</div>
</div>A child is at least --ui-gallery-min-w wide, 20ch by default. Set it on the gallery to change how soon the columns drop: --ui-gallery-min-w: 12rem suits cards, and something like 5rem suits logos.
It can't always avoid a lone child:
- At two columns an odd count still ends on one. The only alternative is a single column, which is worse.
- 13, 21, 25, and 31 children end on one at some widths, because the next count down leaves one alone too.
A few things to know before you rely on it:
- It counts the children that take a cell. Children with
hidden, and<template>,<script>, and<style>, are left out. - It reads the gap from
--gapor--gap-x. It can't see a gap set in a stylesheet or by a primitive, and near a width where the count changes that can let a lone child through. - A child that spans columns with
--col-spanis still counted once, so keep each child to one cell. - A
--grid-colson the gallery at the same breakpoint is ignored. At a higher one it takes over:--display: grid-gallery; --grid-cols--lg: 4is a gallery up tolgand four columns after.
Subgrid
A subgrid is a grid item that lays its own children out on its parent grid's tracks. It needs to be a direct child of a grid, and it needs to span the tracks it wants with --col-span or --row-span.
--display: subgrid-col takes the parent's columns, so a nested row lines up with the cells above it:
<div
style="
--display: grid;
--template-cols: 1fr 2fr 1fr 1fr;
--gap: 2;
--w: 100%;
--max-w: 120;
"
>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
1
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
2
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
3
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
4
</div>
<div
style="
--display: subgrid-col;
--col-span: 4;
"
>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
a
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
b
</div>
<div
data-ui="text-sm"
style="
--col-span: 2;
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
c + d
</div>
</div>
</div>--display: subgrid-row takes the parent's rows. Give each card three rows and the titles, text, and footers stay level, however long one of them runs:
Seen once, at dawn.
RareA resident pair nests in the dead oak every spring and fishes the shallows through October.
CommonHovers over the meadow most afternoons.
Seasonal<div
style="
--display: grid;
--grid-cols: 3;
--gap-x: 4;
--gap-y: 2;
--w: 100%;
--max-w: 160;
"
>
<article
style="
--display: subgrid-row;
--row-span: 3;
--p: 4;
--bg: var(--color-muted);
--radius: 2.5;
"
>
<strong data-ui="text-sm"> Warbler </strong>
<p
data-ui="text-sm"
style="
--m: 0;
--text: var(--color-muted-foreground);
"
>
Seen once, at dawn.
</p>
<span
data-ui="text-xs"
style="
--font-weight: strong;
--text: var(--color-primary);
"
>
Rare
</span>
</article>
<article
style="
--display: subgrid-row;
--row-span: 3;
--p: 4;
--bg: var(--color-muted);
--radius: 2.5;
"
>
<strong data-ui="text-sm"> Great blue heron on the east pond </strong>
<p
data-ui="text-sm"
style="
--m: 0;
--text: var(--color-muted-foreground);
"
>
A resident pair nests in the dead oak every spring and fishes the shallows through October.
</p>
<span
data-ui="text-xs"
style="
--font-weight: strong;
--text: var(--color-primary);
"
>
Common
</span>
</article>
<article
style="
--display: subgrid-row;
--row-span: 3;
--p: 4;
--bg: var(--color-muted);
--radius: 2.5;
"
>
<strong data-ui="text-sm"> Kestrel </strong>
<p
data-ui="text-sm"
style="
--m: 0;
--text: var(--color-muted-foreground);
"
>
Hovers over the meadow most afternoons.
</p>
<span
data-ui="text-xs"
style="
--font-weight: strong;
--text: var(--color-primary);
"
>
Seasonal
</span>
</article>
</div>--display: subgrid takes both, and the children land on the parent's cells:
<div
style="
--display: grid;
--template-cols: 1fr 2fr 1fr;
--gap: 2;
--w: 100%;
--max-w: 120;
"
>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
1
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
2
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
3
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
4
</div>
<div
style="
--display: subgrid;
--col-span: 2;
--row-span: 2;
"
>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
a
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
b
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
c
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-muted-foreground);
--bg: var(--color-muted);
--radius: 2.5;
"
>
d
</div>
</div>
<div
data-ui="text-sm"
style="
--p: 4;
--font-weight: strong;
--text-align: center;
--text: var(--color-primary-foreground);
--bg: var(--color-primary);
--radius: 2.5;
"
>
5
</div>
</div>If the number of children varies, use subgrid-col or subgrid-row. A two-axis subgrid has no spare tracks for the extra ones.
The axis a subgrid does not take keeps its own --grid-cols or --grid-rows. Across breakpoints, the highest one that names a display or a count decides:
--display: grid; --grid-cols: 2; --display--md: subgrid-colis two columns belowmdand the parent's columns from there up.--display: subgrid-col; --grid-cols--lg: 3is the parent's columns up tolgand three columns after.- At the same breakpoint the display wins, so
--display: subgrid-col; --grid-cols: 3ignores the count.
--grid-cols: subgrid and --grid-rows: subgrid no longer exist. The editor and vp run lint:html suggest the rewrite. --template-cols: subgrid and --template-rows: subgrid still work, for an element whose display you can't change.
Plain grid
--display: grid and inline-grid pack their rows at the top instead of stretching them, and --place-content changes that. The flexbox and grid page has the details, along with tracks, placement, and gaps.