Skip to content

Type to search the docs, API, and blog.

↑↓ navigate↵ openesc close
Zazz 0.13 alpha
API navigation

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.

KeywordWhat you get
flex-row, flex-cola flex container and its direction
flex-row-reverse, flex-col-reversethe same, laid out from the far end
inline-flex-row, inline-flex-col, and their -reverse formsan inline flex container and its direction
grid-pilea grid with every direct child in one cell, centered
grid-gallerya grid that picks its column count from its child count
subgrida grid on its parent grid's columns and rows
subgrid-cola grid on its parent grid's columns
subgrid-rowa 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.

--display: flex-row
1
2
3
--display: flex-col
1
2
3
<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.

--display: flex-row-reverse
1
2
3
--display: flex-col-reverse
1
2
3
<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.

grid-pile stacked layer
<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.

--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.

4 children: one row of four, or 2 + 2
1
2
3
4
5 children: one row of five, or 3 + 2
1
2
3
4
5
7 children: 5 + 2, or 4 + 3
1
2
3
4
5
6
7
<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 --gap or --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-span is still counted once, so keep each child to one cell.
  • A --grid-cols on the gallery at the same breakpoint is ignored. At a higher one it takes over: --display: grid-gallery; --grid-cols--lg: 4 is a gallery up to lg and 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:

1
2
3
4
a
b
c + d
<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:

Warbler

Seen once, at dawn.

Rare
Great blue heron on the east pond

A resident pair nests in the dead oak every spring and fishes the shallows through October.

Common
Kestrel

Hovers 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:

1
2
3
4
a
b
c
d
5
<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-col is two columns below md and the parent's columns from there up.
  • --display: subgrid-col; --grid-cols--lg: 3 is the parent's columns up to lg and three columns after.
  • At the same breakpoint the display wins, so --display: subgrid-col; --grid-cols: 3 ignores 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.