Actual CSS

Sizing And Wrapping

Small layout corrections for controls, labels, and compact rails.

Class reference

ClassKindDescription
.fitUtilityShrinks an element to its content width.
.text-nowrapUtilityKeeps text on one line.
.text-wrapUtilityRestores wrapping under a nowrap parent.
.truncateUtilityEllipsizes overflowing single-line text.
.scrollerLayoutTheme-aware scrollbar density and colour.
.scroller.stable-gutterVariantReserves inline-axis scrollbar gutter.

Use .fit when a control or element should shrink to its content instead of filling the available inline space.

<select class="select fit" aria-label="Theme">
  <option>System</option>
  <option>Light</option>
  <option>Dark</option>
</select>

Use .text-nowrap to keep text on one line inside a cell or label, and .text-wrap to let a long label wrap inside a component that keeps its text on one line (.badge). To stop a layout primitive from wrapping — for example to force a .cluster onto a single row — set --cluster-wrap: nowrap.

<div class="cluster tight" style="--cluster-wrap: nowrap;">
  <select class="select sm fit" aria-label="Segment">
    <option>All segments</option>
  </select>
  <button class="btn sm outline" type="button">Filter</button>
</div>

Use .truncate on the flexible item that should ellipsize inside a constrained row.

A long account name that should not push actions away
<header class="cluster" style="--cluster-wrap: nowrap;">
  <strong class="truncate">A long account name that should not push actions away</strong>
  <button class="btn sm ghost" type="button">Open</button>
</header>
.fit {
  inline-size: fit-content;
  max-inline-size: 100%;
}

.text-nowrap {
  white-space: nowrap;
}

.truncate {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Scroller

Use .scroller to apply optional framework overflow treatment to a scroll container: a quieter scrollbar. It does not create overflow; pair it with .overflow-auto or a component that already creates overflow.

The engine keeps drawing the scrollbar; .scroller only hands it a density and a colour that follow the theme. There is no ::-webkit-scrollbar chrome: rebuilding a thumb by hand means re-implementing the hover, the corner and the light/dark adaptation that color-scheme already provides, and the hand-built version never quite matches the native one anyway.

scrollbar-color and scrollbar-width land in Chromium 121 and Safari 18.2, above the capability floor. An engine that knows neither ignores both declarations and draws its native scrollbar — the intended fallback, not a broken state.

.scroller does not apply to touch screens, where the native overlay scrollbar stays: it hides at rest, where a styled bar would stay visible.

.scroller is a layout primitive, so it comes with actual.full.css and with actual-css/css/layout like .stack or .cluster. A project importing module by module reaches it directly:

@import "actual-css/css/layout/scroller";

Scrollable content keeps the native scrollbar but makes it quieter.

Long content can keep flowing without forcing every component to invent its own scrollbar rules.

The utility exposes local custom properties for one-off tuning.

<div class="overflow-auto scroller" style="max-block-size: 12rem">
  <div class="stack">
    <p>Scrollable content keeps the native scrollbar but makes it quieter.</p>
    <p>Long content can keep flowing without forcing every component to invent its own scrollbar rules.</p>
    <p>The utility exposes local custom properties for one-off tuning.</p>
  </div>
</div>
.scroller {
  --scroller-track: transparent;
  --scroller-thumb: var(--border);
}

@media not all and (pointer: coarse) {
  .scroller {
    scrollbar-color: var(--scroller-thumb) var(--scroller-track);
    scrollbar-width: thin;
  }
}

Customize locally when a scroll surface needs more contrast:

<div class="overflow-auto scroller" style="--scroller-thumb: var(--text-muted)">
  ...
</div>

Thickness is not a hook: scrollbar-width takes thin or auto, not a length. Hover is left to the engine — it varies by platform, and matching it by hand was the part of a custom scrollbar that never held up.

One-row strips

Components that never wrap scroll horizontally when they do not fit: .tabs, .steps-horizontal, and .table-wrap. (.breadcrumb truncates its labels instead; see Breadcrumb. .pagination wraps.) In supporting browsers, a strip that loads on a current link tab or step starts scrolled to it; elsewhere it starts at its first item.

.tabs hides its scrollbar and fades its edges instead: selecting the clipped tab scrolls it into view. The others leave the scrollbar to the engine, so an OS-default horizontal scrollbar can sit under a short strip, and on touch screens it overlays the strip and hides at rest, leaving a clipped item as the cue that the strip continues. Put .scroller on the strip itself — the element that scrolls — for a thin, theme-coloured bar under a mouse; touch keeps the overlay. These strips have no edge fade (overflow shadow, scroll hint): the clipped item and the scrollbar already say there is more. Keyboard focus stops an item with its focus line inside the strip.

<ol class="steps steps-horizontal scroller">

There is no class that hides the scrollbar: on a strip whose items do not scroll it themselves, it is the only visible scroll control for a mouse without a horizontal wheel. Apply .scroller to every such strip of a page, or to none, so the bars stay consistent.

A strip keeps scrolling inside a flex or grid row, such as a label and link tabs on one .cluster: a <nav> directly around .tabs shrinks with the row (and around .breadcrumb, which then truncates). Any other wrapper needs min-inline-size: 0, or the row pushes the whole page into scrolling.

<div class="cluster">
  <span>Sections</span>
  <nav aria-label="Account sections"><ul class="tabs">…</ul></nav>
</div>

CSS hooks

  • --scroller-track — scrollbar track color.
  • --scroller-thumb — scrollbar thumb color.
Actual CSS

Search documentation