Actual CSS

Cluster

Inline groups that wrap naturally, useful for action rows, tags, and toolbars.

Read docs
<div class="cluster">
  <button class="btn primary" type="button">Save</button>
  <button class="btn outline" type="button">Cancel</button>
  <a href="#">Read docs</a>
</div>

Use cluster for action rows, tags, toolbar sections, metadata, and compact navigation.

Cluster owns its children's spacing: direct-child margins are reset, so spacing between items always comes from --gap. Unlike .stack, which resets only the block axis, cluster resets margins on both axes — a wrapping cluster's gap controls inline spacing between items and block spacing between wrapped rows.

Action rows

Actions are content; the cluster owns the geometry. A semantic action list is a <menu> (or <ul>) with .cluster:

  • <menu class="cluster">
      <li><button class="btn primary" type="button">Save</button></li>
      <li><button class="btn outline" type="button">Cancel</button></li>
    </menu>

    There is no .actions class. A dense row is cluster tight; a vertical action list is stack list-reset.

    List chrome

    .cluster neutralizes the native chrome of a <ul>, <ol> or <menu> it is applied to. The element stays a list in the DOM and for assistive technology, but a horizontal, wrapping group cannot carry markers and indentation meaningfully, so they are removed. .stack makes no such change — an <ol class="stack"> keeps its numbers. Use .list-reset alone for a plain list with no layout.

    CSS hooks

    • --cluster-justify — main-axis distribution (justify-content).
    • --cluster-align — cross-axis alignment (align-items).
    • --cluster-wrap — wrapping behavior (flex-wrap); set to nowrap to force a single row.
    • --gap — space between items.

    Split / spread

    For split/spread layouts — two items apart, at opposite ends, or "one left / one right" — use .cluster with --cluster-justify: space-between. There is no separate .split or .spread primitive; this is the same relationship.

    Results

    <div class="cluster" style="--cluster-justify: space-between">
      <h2>Results</h2>
      <button class="btn primary" type="button">New search</button>
    </div>

    Once the row wraps, space-between puts an item alone on its line at the start. To keep the end item on the end edge when it wraps, add .margin-inline-start-auto to it.

    To align a row to its top edge instead of centering it — useful when one item wraps to several lines — set --cluster-align on the cluster itself.

    .cluster.filters {
      --cluster-align: start;
      --cluster-justify: space-between;
    }
    

    The optional utility layer ships .justify-content-start, .justify-content-center, .justify-content-end and .justify-content-space-between. They set justify-content on that one row only; a nested .cluster keeps its own alignment. The --cluster-* hooks behave the same way: each cluster resets them, so a value applies to the cluster it is set on and never to a nested one. To align nested rows, select them (.toolbar > .cluster). --gap keeps inheriting, so a density context still reaches every nested cluster. See the utilities page.

    Controls inside a wrapping cluster

    A form control (--control-size, full width) inside a wrapping cluster claims the full line and pushes every sibling to its own row. To keep a row of controls under one label, set --cluster-wrap: nowrap and give the controls min-inline-size: 0 (and flex: 1 1 0% to share the row evenly).

    Actual CSS

    Search documentation