Skip to main content

Containers

Layout containers for common page patterns.

Spread container

Flexbox container with title on the left and actions on the right:

Example title

<div class="l-ui-spread">
  <h1>Example title</h1>
  <button class="l-ui-button l-ui-button--primary">New</button>
</div>

Grid container

Responsive grid that stacks on mobile and switches to two columns on medium screens:

First item

Grid items stack vertically on mobile.

Second item

On medium screens they sit side by side.

Third item

Additional items wrap to the next row.

Fourth item

The grid fills evenly with consistent gaps.

<div class="l-ui-grid">
  <div class="l-ui-surface">First</div>
  <div class="l-ui-surface">Second</div>
  <div class="l-ui-surface">Third</div>
  <div class="l-ui-surface">Fourth</div>
</div>

Contained width

Wrap page content in l-ui-page__contained to cap its width and centre it. The cap is the --l-ui-contained-width token (default 80rem), the same token read by the contained header (l-ui-body--header-contained), so the two line up. Override the token once - on :root, a container, or inline - to move both. The example below sets it to 40rem so the centring is visible at any screen width:

Centred, capped content

This column never grows past --l-ui-contained-width and centres in the available space.

<div class="l-ui-page__contained">
  <!-- capped at --l-ui-contained-width (default 80rem), centred -->
</div>

<!-- move the header and page content together: -->
:root { --l-ui-contained-width: 72rem; }

By default the contained column keeps the page gutter, so its content lines up with the rest of the page. Add l-ui-page__contained--no-gutter to opt out: the column reaches the page edge while it is narrower than --l-ui-contained-width, then centres and caps once there is room. This is useful for content that should run flush on small screens - tables, media, or full-width cards - without losing the width cap on large ones. The example keeps the 40rem cap so the centred state is visible:

Flush, then capped

This column has no gutter: it runs to the page edge until it reaches --l-ui-contained-width, then centres.

<div class="l-ui-page__contained--no-gutter">
  <!-- flush to the page edge until --l-ui-contained-width, then centred -->
</div>

Full-bleed

The page applies a gutter (the --l-ui-gutter custom property, default 1rem) as its horizontal and bottom padding, shared with the header so the two always align. Add l-ui-bleed to a single child to break it out to the page edge - a full-bleed hero or banner - without reverse-engineering the padding. It cancels exactly the current gutter, so there are no magic numbers to match. It affects the horizontal edges only; content still sits below the page's top padding. To pull the first section up to the very top of the viewport - behind the header - add l-ui-body--flush-top to the body and pair it with l-ui-body--glass-header (see Header).

Padded page content sits within the gutter.

This banner uses l-ui-bleed to reach the page edge.

Content after the banner returns to the gutter.

<p>Padded page content sits within the gutter.</p>
<div class="l-ui-bleed bg-surface px-6 py-8">
  This banner uses l-ui-bleed to reach the page edge.
</div>
<p>Content after the banner returns to the gutter.</p>

CSS classes

Container CSS classes
Class Description
l-ui-spread Flexbox with space-between alignment
l-ui-grid Responsive grid, stacked on mobile, two columns on md
l-ui-page__contained Centred column capped at --l-ui-contained-width (default 80rem)
l-ui-page__contained--no-gutter Contained column that runs flush to the page edge until it reaches the cap, then centres
l-ui-bleed Breaks a child out to the page edge (full-bleed hero or banner)
l-ui-table-container Scrollable container for tables
l-ui-checkbox-container Flexbox container for checkboxes and their labels
l-ui-pagy-container Container for Pagy pagination