Grid
<cw-grid> | CwGrid
Lays its children out in columns, one child per cell, dropping to fewer columns as it narrows.
<cw-grid> arranges its children in columns, one child per cell, filling rows from the
start. There are no wrappers to add: each direct child is a cell.
Columns respond to the grid’s own width, not the viewport’s, so the same grid works in a full-width page band and in a narrow sidebar without any breakpoints to tune.
<cw-grid columns="3" min-column-width="10rem"> <div class="grid-box">One</div> <div class="grid-box">Two</div> <div class="grid-box">Three</div> <div class="grid-box">Four</div> <div class="grid-box">Five</div> <div class="grid-box">Six</div> </cw-grid> <style> .grid-box { padding: var(--cw-spacing-large); border-radius: var(--cw-border-radius-medium); background: var(--cw-color-primary-100); color: var(--cw-color-primary-800); font-weight: var(--cw-font-weight-semibold); } </style>
import CwGrid from '@cordwainer/cw-elements/dist/react/grid'; const css = ` .grid-box { padding: var(--cw-spacing-large); border-radius: var(--cw-border-radius-medium); background: var(--cw-color-primary-100); color: var(--cw-color-primary-800); font-weight: var(--cw-font-weight-semibold); } `; const App = () => ( <> <CwGrid columns="3" minColumnWidth="10rem"> <div className="grid-box">One</div> <div className="grid-box">Two</div> <div className="grid-box">Three</div> <div className="grid-box">Four</div> <div className="grid-box">Five</div> <div className="grid-box">Six</div> </CwGrid> <style>{css}</style> </> );
A grid takes the full width of its container. Put it in a block context, such as a page section, a card’s body or a stretched flex item, rather than an inline one.
See Page Layout for how sections, grids and stacks combine into a full page.
Examples
Equal Columns
Set columns to a count from 1 to 6. The default is 2.
The count is a maximum, not a fixed number. Whenever a column would be narrower than
min-column-width (15rem by default), the grid drops a column, so a four-column
grid becomes three, then two, then one as it narrows. A partly filled last row keeps the same item width as
the rows above it.
Drag the bottom-right corner of the box below to resize it. This example sets
min-column-width="7rem" so all four columns fit in this page’s content column; most other
examples here lower it too.
<div class="grid-resizer"> <cw-grid columns="4" min-column-width="7rem"> <div class="grid-box">One</div> <div class="grid-box">Two</div> <div class="grid-box">Three</div> <div class="grid-box">Four</div> <div class="grid-box">Five</div> <div class="grid-box">Six</div> </cw-grid> </div> <style> .grid-resizer { resize: horizontal; overflow: auto; max-width: 100%; min-width: 8rem; padding: var(--cw-spacing-small); border: dashed 1px var(--cw-color-neutral-400); } </style>
import CwGrid from '@cordwainer/cw-elements/dist/react/grid'; const css = ` .grid-resizer { resize: horizontal; overflow: auto; max-width: 100%; min-width: 8rem; padding: var(--cw-spacing-small); border: dashed 1px var(--cw-color-neutral-400); } `; const App = () => ( <> <div className="grid-resizer"> <CwGrid columns="4" minColumnWidth="7rem"> <div className="grid-box">One</div> <div className="grid-box">Two</div> <div className="grid-box">Three</div> <div className="grid-box">Four</div> <div className="grid-box">Five</div> <div className="grid-box">Six</div> </CwGrid> </div> <style>{css}</style> </> );
Grid of Cards
Items in a row stretch to the height of the tallest one by default, so cards with different amounts of content still line up.
Accessible, themeable components built on web standards.
Color, spacing and typography tokens you can override per theme.
Works anywhere HTML does, with generated wrappers for React and a manifest for page builders that read one.
<cw-grid columns="3" min-column-width="10rem" class="grid-cards"> <cw-card> <strong>Components</strong><br /> Accessible, themeable components built on web standards. </cw-card> <cw-card> <strong>Tokens</strong><br /> Color, spacing and typography tokens you can override per theme. </cw-card> <cw-card> <strong>Frameworks</strong><br /> Works anywhere HTML does, with generated wrappers for React and a manifest for page builders that read one. </cw-card> </cw-grid> <style> .grid-cards cw-card::part(base) { height: 100%; } </style>
import CwCard from '@cordwainer/cw-elements/dist/react/card'; import CwGrid from '@cordwainer/cw-elements/dist/react/grid'; const css = ` .grid-cards cw-card::part(base) { height: 100%; } `; const App = () => ( <> <CwGrid columns="3" minColumnWidth="10rem" className="grid-cards"> <CwCard> <strong>Components</strong> <br /> Accessible, themeable components built on web standards. </CwCard> <CwCard> <strong>Tokens</strong> <br /> Color, spacing and typography tokens you can override per theme. </CwCard> <CwCard> <strong>Frameworks</strong> <br /> Works anywhere HTML does, with generated wrappers for React and a manifest for page builders that read one. </CwCard> </CwGrid> <style>{css}</style> </> );
The grid stretches each card’s host element. A card draws its border on its base part, so
give that part height: 100% too, as above, to make the visible cards equal height.
Ratio Splits
Set columns to a ratio to size columns in proportion: 2-1, 1-2,
3-1, 1-3, 2-1-1, 1-2-1 or 1-1-2. A
2-1 grid suits a main column beside a sidebar.
Ratio splits stack below 40rem by default (see below), which is wider than this page’s content
column, so the ratio examples here lower that threshold to 25rem with
--cw-grid-stack-below.
<cw-grid columns="2-1" style="--cw-grid-stack-below: 25rem;"> <div class="grid-box">Main content</div> <div class="grid-box">Sidebar</div> </cw-grid> <br /> <cw-grid columns="1-2-1" style="--cw-grid-stack-below: 25rem;"> <div class="grid-box">Aside</div> <div class="grid-box">Main content</div> <div class="grid-box">Aside</div> </cw-grid>
import CwGrid from '@cordwainer/cw-elements/dist/react/grid'; const App = () => ( <> <CwGrid columns="2-1" style={{ '--cw-grid-stack-below': '25rem' }}> <div className="grid-box">Main content</div> <div className="grid-box">Sidebar</div> </CwGrid> <br /> <CwGrid columns="1-2-1" style={{ '--cw-grid-stack-below': '25rem' }}> <div className="grid-box">Aside</div> <div className="grid-box">Main content</div> <div className="grid-box">Aside</div> </CwGrid> </> );
A ratio split doesn’t step down through narrower column counts, since a 2-1 layout squeezed
into equal columns would read as a different layout. It stays split until the grid is narrower than
--cw-grid-stack-below (40rem by default), then stacks every child into one column,
in source order. Resize the box to see it stack below 25rem.
<div class="grid-resizer"> <cw-grid columns="2-1" style="--cw-grid-stack-below: 25rem;"> <div class="grid-box">Main content</div> <div class="grid-box">Sidebar</div> </cw-grid> </div>
import CwGrid from '@cordwainer/cw-elements/dist/react/grid'; const App = () => ( <div className="grid-resizer"> <CwGrid columns="2-1" style={{ '--cw-grid-stack-below': '25rem' }}> <div className="grid-box">Main content</div> <div className="grid-box">Sidebar</div> </CwGrid> </div> );
With more children than the split has columns, the ratio repeats on each row.
Inside a Narrow Container
Because a grid responds to its own width, the same columns="3" grid that fills a wide page
drops to a single column inside a narrow sidebar, even on a wide screen.
<div class="grid-sidebar"> <cw-grid columns="3"> <div class="grid-box">One</div> <div class="grid-box">Two</div> <div class="grid-box">Three</div> </cw-grid> </div> <style> .grid-sidebar { max-width: 18rem; padding: var(--cw-spacing-medium); border: solid 1px var(--cw-color-neutral-200); border-radius: var(--cw-border-radius-medium); } </style>
import CwGrid from '@cordwainer/cw-elements/dist/react/grid'; const css = ` .grid-sidebar { max-width: 18rem; padding: var(--cw-spacing-medium); border: solid 1px var(--cw-color-neutral-200); border-radius: var(--cw-border-radius-medium); } `; const App = () => ( <> <div className="grid-sidebar"> <CwGrid columns="3"> <div className="grid-box">One</div> <div className="grid-box">Two</div> <div className="grid-box">Three</div> </CwGrid> </div> <style>{css}</style> </> );
Minimum Column Width
Use min-column-width to set how narrow an equal column can get before the grid drops one. It
takes any CSS length. Smaller values keep more columns on narrow screens; larger ones drop columns sooner.
<cw-grid columns="6" min-column-width="4rem"> <div class="grid-box">1</div> <div class="grid-box">2</div> <div class="grid-box">3</div> <div class="grid-box">4</div> <div class="grid-box">5</div> <div class="grid-box">6</div> </cw-grid>
import CwGrid from '@cordwainer/cw-elements/dist/react/grid'; const App = () => ( <CwGrid columns="6" minColumnWidth="4rem"> <div className="grid-box">1</div> <div className="grid-box">2</div> <div className="grid-box">3</div> <div className="grid-box">4</div> <div className="grid-box">5</div> <div className="grid-box">6</div> </CwGrid> );
Gap
Use gap to set the space between rows and columns. It takes a
spacing token name, from 3x-small to 4x-large. The
default is large.
<cw-grid columns="3" gap="x-small" min-column-width="8rem"> <div class="grid-box">One</div> <div class="grid-box">Two</div> <div class="grid-box">Three</div> </cw-grid> <br /> <cw-grid columns="3" gap="3x-large" min-column-width="8rem"> <div class="grid-box">One</div> <div class="grid-box">Two</div> <div class="grid-box">Three</div> </cw-grid>
import CwGrid from '@cordwainer/cw-elements/dist/react/grid'; const App = () => ( <> <CwGrid columns="3" gap="x-small" minColumnWidth="8rem"> <div className="grid-box">One</div> <div className="grid-box">Two</div> <div className="grid-box">Three</div> </CwGrid> <br /> <CwGrid columns="3" gap="3x-large" minColumnWidth="8rem"> <div className="grid-box">One</div> <div className="grid-box">Two</div> <div className="grid-box">Three</div> </CwGrid> </> );
An unknown gap, columns or align value falls back to the default
and logs a warning to the console naming the value, so a typo never silently changes the layout.
Alignment
Use align to position items vertically within their row: stretch (the default),
start, center or end.
that sets
the row’s height
<cw-grid columns="3" align="center" min-column-width="8rem"> <div class="grid-box">Short</div> <div class="grid-box">A taller item<br />that sets<br />the row's height</div> <div class="grid-box">Short</div> </cw-grid>
import CwGrid from '@cordwainer/cw-elements/dist/react/grid'; const App = () => ( <CwGrid columns="3" align="center" minColumnWidth="8rem"> <div className="grid-box">Short</div> <div className="grid-box"> A taller item <br /> that sets <br /> the row's height </div> <div className="grid-box">Short</div> </CwGrid> );
Spanning Columns
To make one item span more than one equal column, set grid-column on it directly. Spans work
against the automatic column drop: an item spanning two columns still asks for two once the grid is down to
one, so keep spans for grids that stay wide. Ratio splits don’t support spans.
<cw-grid columns="3" min-column-width="8rem"> <div class="grid-box" style="grid-column: span 2;">Spans two columns</div> <div class="grid-box">One</div> <div class="grid-box">One</div> <div class="grid-box">One</div> <div class="grid-box">One</div> </cw-grid>
import CwGrid from '@cordwainer/cw-elements/dist/react/grid'; const App = () => ( <CwGrid columns="3" minColumnWidth="8rem"> <div className="grid-box" style={{ gridColumn: 'span 2' }}> Spans two columns </div> <div className="grid-box">One</div> <div className="grid-box">One</div> <div className="grid-box">One</div> <div className="grid-box">One</div> </CwGrid> );
Changing the Stack Threshold
Set --cw-grid-stack-below to change where ratio splits stack. Set it on :root to
change it for every grid, or on one grid as below, which stays split down to 20rem.
<div class="grid-resizer"> <cw-grid columns="1-2" style="--cw-grid-stack-below: 20rem;"> <div class="grid-box">Aside</div> <div class="grid-box">Main content</div> </cw-grid> </div>
import CwGrid from '@cordwainer/cw-elements/dist/react/grid'; const App = () => ( <div className="grid-resizer"> <CwGrid columns="1-2" style={{ '--cw-grid-stack-below': '20rem' }}> <div className="grid-box">Aside</div> <div className="grid-box">Main content</div> </CwGrid> </div> );
Importing
If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.
To import this component from the CDN using a script tag:
<script type="module" src="https://cdn.jsdelivr.net/npm/@cordwainer/cw-elements@1.6.0/cdn/components/grid/grid.js"></script>
To import this component from the CDN using a JavaScript import:
import 'https://cdn.jsdelivr.net/npm/@cordwainer/cw-elements@1.6.0/cdn/components/grid/grid.js';
To import this component using a bundler:
import '@cordwainer/cw-elements/dist/components/grid/grid.js';
To import this component as a React component:
import CwGrid from '@cordwainer/cw-elements/dist/react/grid';
Slots
| Name | Description |
|---|---|
| (default) | The grid’s items. Each direct child is one cell, filled in rows from the start. |
Learn more about using slots.
Properties
| Name | Description | Reflects | Type | Default |
|---|---|---|---|---|
columns
|
The number of columns. An equal count (1–6) is a maximum: the grid drops
to fewer columns whenever a column would be narrower than min-column-width. A ratio
split (2-1, 1-2, 3-1, 1-3, 2-1-1,
1-2-1, 1-1-2) sizes its columns in that proportion and stacks them into
one column below --cw-grid-stack-below.
|
|
'1' | '2' | '3' | '4' | '5' | '6' | '2-1' | '1-2' | '3-1' | '1-3' | '2-1-1' | '1-2-1' |
'1-1-2'
|
'2'
|
minColumnWidth
min-column-width
|
The narrowest an equal column can get before the grid drops a column, as a CSS length. Has no effect on ratio splits. |
string
|
'15rem'
|
|
gap
|
The space between rows and columns, as a spacing token name. |
|
'3x-small' | '2x-small' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large' | '2x-large' |
'3x-large' | '4x-large'
|
'large'
|
align
|
How items are aligned vertically within their row. stretch makes every item in a row as
tall as the tallest, so cards in a row are equal height.
|
|
'stretch' | 'start' | 'center' | 'end'
|
'stretch'
|
updateComplete |
A read-only promise that resolves when the component has finished updating. |
Learn more about attributes and properties.
Custom Properties
| Name | Description | Default |
|---|---|---|
--cw-grid-stack-below |
Ratio splits stack into a single column when the grid is narrower than this. Set it on
:root to change it everywhere, or on one grid.
|
40rem |
Learn more about customizing CSS custom properties.
Parts
| Name | Description |
|---|---|
base |
The component’s base wrapper, which lays out the slotted items. |
Learn more about customizing CSS parts.