Skip to main content
Copy for LLM

Grid

A CSS grid layout with responsive column support. Accepts a compact string syntax for breakpoint-based column counts.

Basic Usage

3-column grid
One
Two
Three

Responsive Columns

Pass a space-separated string with breakpoint prefixes. The syntax mirrors Tailwind's responsive convention.

Responsive: 1 col → 2 on sm → 3 on lg
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6

Gap Sizes

Large gap
First
Second
No gap
One
Two
Three

gap names a rung on the --space-wk-* ladder. A grid of cards that should match the spacing inside WireKit's own components takes the tighter --gap-wk-* ladder instead with scale="gap". The rung names stay the same and the values from md up are smaller, as the note under Props shows.

The tighter gap ladder
One
Two
Three

Alignment

Center-aligned grid items
Short
This card has more content to demonstrate vertical alignment across grid items
Short

Semantic Elements

Grid as section
Left column
Right column

Responsive Syntax

The cols prop accepts a space-separated string where each token is either a plain number (base columns) or a breakpoint:number pair:

cols="1"              → grid-cols-1
cols="1 sm:2 lg:3"   → grid-cols-1 sm:grid-cols-2 lg:grid-cols-3
cols="2 xl:4"         → grid-cols-2 xl:grid-cols-4

Supported breakpoints follow Tailwind's defaults: sm, md, lg, xl, 2xl.

Columns That Follow the Content

cols counts columns against the viewport. min counts them against the container: you give the narrowest a column may be, and as many fit as fit — one on a narrow screen.

The difference is invisible until the container is narrower than the window. Open a sidebar, use a split view, drop the grid inside a card, and a cols="1 md:2 lg:3" grid keeps rendering three columns because the window is still wide. A min grid reflows, because it is measuring the box the cards are actually in.

This is the ordinary responsive card grid, so reach for it first and keep cols for the cases where the column count is genuinely a design decision per breakpoint.

A card grid that reflows with its container

Sessions

1,284 this week

Signups

96 this week

Revenue

€ 18,400

Churn

1.2 %

min takes any CSS length — 14rem, 20ch, 280px. A column never overflows its container: below its own minimum the grid drops to a single column instead.

min and template ride in an inline style, so a strict Content-Security-Policy can remove them. Both take arbitrary values, and an arbitrary value cannot become a class: Tailwind extracts class names from source text, and a track built at runtime leaves its scanner nothing to find. Under a style-src policy without 'unsafe-inline' — Level 3 spells it style-src-attr — the browser drops the attribute.

Elsewhere a dropped inline style costs a shade or a width. Here it costs the whole statement: with no track and no columns, the grid stacks into a single column.

Pass cols alongside the track prop and that is what you fall back to:

{{-- The track when the policy allows it; three equal columns when it does not. --}}
<x-wirekit::grid cols="3" min="14rem"> … </x-wirekit::grid>

The inline style wins on specificity whenever it is allowed, so the cols classes change nothing about what you normally see — they decide what is left when the style never arrives. Approximate by construction, and far better than one column.

A template with a breakpoint cannot fall back this way, and it is better to know before the policy ships. Its values still ride in the inline style, as custom properties, but a class reads them — so at a breakpoint the template occupies there is no cols class to fall back to, and without the style the class resolves to no tracks at all. Under a strict policy, keep the responsive layout in cols and use template only where the policy allows inline styles.

Columns of Different Widths

cols only knows equal columns. The two commonest application layouts are neither: the three-pane workspace (navigation, content, detail) and the week grid (a time axis plus seven days). template takes an explicit track list and hands it to CSS as written.

The three-pane workspace

Navigation

Content — this pane takes whatever is left

Detail

This preview is designed for larger viewports. Open this page on a desktop to try the live, interactive demo.

Anything grid-template-columns accepts works: lengths, fr, auto, min-content, max-content, minmax(), repeat(), fit-content().

A template without a breakpoint is that wide at every viewport, and that is what asking for exact tracks means. Unlike min, it is handed to CSS as written. The example above reserves 10rem + 8rem before the content pane gets anything: on a 390 px phone that leaves the middle column a few characters wide and pushes the grid past the screen edge. Nothing warns you — it renders, it is simply unreadable.

Do not use a bare track list for a layout that has to work on a phone. Give it a breakpoint instead, as below, or prefer min if every track can flex — it collapses to one column instead of overflowing.

A track list that switches at a breakpoint

The layout applications reach for most: one column on a phone, and from lg a flexible column beside a fixed aside. Prefix a track list with a breakpoint and put it in brackets, an underscore standing for each space — the same spelling a hand-written lg:grid-cols-[…] uses. Tokens without a prefix are the base, and cols fills every breakpoint the template leaves free.

One column on a phone, content and aside from lg

Content — the whole width on a phone, whatever is left beside the aside from lg

Aside — below the content on a phone, 14rem beside it from lg

{{-- 1. One column below lg, two tracks from lg --}}
<x-wirekit::grid cols="1" template="lg:[minmax(0,1fr)_20rem]">…</x-wirekit::grid>

{{-- 2. A base and two breakpoints: two tracks, then the three-pane workspace --}}
<x-wirekit::grid template="1fr md:[1fr_16rem] xl:[14rem_1fr_18rem]">…</x-wirekit::grid>

Keep cols="1" for the phone when the template starts at a breakpoint. It is the one column definition the grid has below that breakpoint, and it is what lets a long word wrap: without it the column sizes itself to its widest unbreakable content, and the page scrolls sideways.

template="14rem 1fr 18rem"                  → navigation | content | detail
template="4.5rem repeat(7, minmax(0, 1fr))" → time axis + seven days
template="1fr 1fr 1fr auto"                 → three equal columns and a trailing action

Which of the three to use

You want Prop
A specific column count per breakpoint cols
As many columns as fit, at least this wide min
Columns of different, named widths — at every width, or switching at a breakpoint template

Only one column track can exist, so the props do not combine: template wins over min, and min wins over cols.

Props

Prop Type Default Description
cols string|int 1 Column count. Integer or responsive string: "1 sm:2 lg:3"
min string|null null Minimum column width for a content-driven grid: "14rem". Wins over cols
template string|null null Explicit column track list: "14rem 1fr 18rem". Takes breakpoints in brackets, _ for each space: "lg:[1fr_20rem]". Wins over min and cols
gap string 'md' Spacing: none, xs, sm, md, lg, xl, 2xl
scale string 'space' Which spacing ladder gap names a rung on: space (the default, unchanged) or gap for the tighter --gap-wk-* ladder — see the note below the props
align string|null null Vertical alignment: start, center, end, stretch
as string 'div' HTML element to render
scope string|null null Scoped personalization name

The rung names are shared with a second ladder, and the values are not. scale="space" (the default) reads --space-wk-*; scale="gap" reads the tighter --gap-wk-* ladder, which uses the same xs…2xl labels with different values from md up and is what WireKit's own components read for spacing inside a component. The rung name alone does not tell you which — gap="md" is 1rem on one ladder and 0.75rem on the other — so changing scale without changing gap re-spaces the container on purpose, and swapping a raw utility for a rung of the same name re-spaces it by accident. See Two spacing ladders, same rung names.

Rung scale="space" (default) scale="gap"
xs 0.25rem 0.25rem
sm 0.5rem 0.5rem
md 1rem 0.75rem
lg 1.5rem 1rem
xl 2.5rem 1.5rem
2xl 4rem 2rem

Keyboard Interaction

This component is a layout wrapper. Keyboard interaction is delegated to its children.

Design Tokens

Same spacing tokens as Stack and Row.

Updated in WireKit v2.67.0 (2026-10-15)

Was this page helpful?

Thank you for your feedback!

Voting requires cookies or local storage. What we store