Skip to content

Grid

A responsive layout on twelve columns. GridContainer sets the column count and the gutters; Grid says how many columns a cell takes.

tsx
import { Grid, GridContainer } from 'neba';

<GridContainer spacing={3}>
  <Grid span={{ xs: 12, md: 8 }}>Body</Grid>
  <Grid span={{ xs: 12, md: 4 }}>Sidebar</Grid>
</GridContainer>;

GridContainer draws no surface, so it has no variant, color or elevation. Wrap it in a Box or a Card when the sheet is wanted.

Props

GridContainer

PropTypeDefaultDescription
columnsnumber | Partial<Record<NebaBreakpoint, number>>12How many columns a row divides into. Every span and offset inside is read against this number
spacingnumber | Partial<Record<NebaBreakpoint, number>>2The gutter between items, on Tailwind's spacing scale: 4 is 1rem. Fractions are allowed: 1.5 is 0.375rem
rowSpacingnumber | Partial<Record<NebaBreakpoint, number>>spacingThe gutter between rows only
columnSpacingnumber | Partial<Record<NebaBreakpoint, number>>spacingThe gutter between columns only
justifyContent'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly' | 'stretch'How a row distributes the space its items did not use. A prop of its own, not something to reach for sx or className for
alignItems'start' | 'center' | 'end' | 'stretch' | 'baseline''stretch'How items sit across the row. The default stretches, so a row of cards is a row of one height
alignContent'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly' | 'stretch'Where the rows sit when the grid is shorter than the box holding it. Only visible on a container with a height of its own
wrapbooleantrueWhether a row that runs out of columns continues on the next one. Off gives one overflowing row, which is what a scrolling strip wants
paddedbooleantrueInner padding. Turn it off when the grid already sits inside something that pads: a Container, a Card, another grid
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl''md'The padding's scale. As on Box it never touches a height or the type scale, and it is not the gutter: that is spacing
densityshared'default' | 'compact''default'Padding only
renderuseRender.RenderPropRenders something other than a div (<section />). Base UI's own escape hatch
childrenReactNodeThe Grid items

Grid

PropTypeDefaultDescription
spanGridSpan | Partial<Record<NebaBreakpoint, GridSpan>>a full rowHow many of the container's columns the item takes. Per-breakpoint as { xs: 12, md: 6 }. A span wider than the row is clamped to the row rather than overflowing. 'auto' is as wide as the contents and 'grow' takes the space the row has left
offsetnumber | Partial<Record<NebaBreakpoint, number>>0Columns left empty ahead of the item: space pushed in before it, not an absolute position counted from the start of the row
alignSelf'auto' | 'start' | 'center' | 'end' | 'stretch' | 'baseline'Overrides the row's alignItems for this item alone
renderuseRender.RenderPropRenders something other than a div (<li />). Base UI's own escape hatch
childrenReactNodeWhat the cell holds

Both pass every native <div> attribute straight through.

Examples

span

span is read against the container's column count. On the default twelve, span={6} is a half; with columns={24} the same 6 is a quarter.

The width is (100% + gutter) × span / columns − gutter, so twelve span={1} cells and one span={12} end on exactly the same pixel.

auto · grow

Two widths are not a share of twelve. span="auto" is as wide as what is in the cell — an avatar, a chip, a button at the end of a row — and span="grow" is that plus everything the row has left over, which is how a title sits between the two.

Both mix with numbers in one responsive map — the contents' width on a phone, a third of the row from 48rem up:

tsx
<Grid span={{ xs: 'auto', md: 4 }}>Reference</Grid>

breakpoints

Give span an object and it uses a different value per width. Every entry applies from its own breakpoint up (it is a floor, not a band), which is what makes two of them enough to describe a whole layout.

The widths are Tailwind's own defaults: sm 40rem · md 48rem · lg 64rem · xl 80rem. xs is 0, the value with no media query around it, so a grid and a md: utility change at the same moment.

columns · spacing · rowSpacing · columnSpacing · offset all take responsive values the same way.

spacing · rowSpacing · columnSpacing

spacing is on Tailwind's spacing scale. spacing={4} is 1rem, the same length as gap-4 or Box's p-4. Fractions are allowed, so spacing={1.5} is 0.375rem.

rowSpacing and columnSpacing each override one axis.

columns

The column count. Twelve is the default, but it does not divide by five, so values like 24 are useful. Every span and offset beneath the container is read against this number. A span wider than the row is clamped to the row rather than overflowing.

offset

Empty columns pushed in ahead of the item: space inserted in front of it rather than an absolute position counted from the start of the row. After an item that already took columns, the offset pushes on from there.

justifyContent · alignItems · alignContent · alignSelf

Alignment is set through props rather than a className. The first three live on GridContainer, alignSelf on Grid.

The values are start / center / end, which flip under RTL. Distribution values like space-between keep their CSS spelling.

padded

spacing is the space between items; padded is the padding around the grid. It defaults to true, so turn it off inside a Container, a Card or another grid.

size and density set how much.

Nesting

A grid inside a grid is a GridContainer inside a Grid. The inner grid re-divides the width its cell was given, so span={6} in there is half of a half.

Released under the MIT License