Grid lays out direct children in two dimensions. Use it when a layout needs explicit columns,
rows, or named areas. Use Stack or Cluster
when children flow on one axis. Read Layout to choose a
layout component.
Pass a number to columns for that many equal columns. Each column can shrink below the width of
its content, so long content wraps instead of widening one column.
import { Grid } from '@luke-ui/react/grid' ;
import { ExampleItem } from '#docs' ;
export default () => {
return (
< Grid columns ={ 2 } gap = "space.12" >
< ExampleItem >First</ ExampleItem >
< ExampleItem >Second</ ExampleItem >
< ExampleItem >Third</ ExampleItem >
< ExampleItem >Fourth</ ExampleItem >
</ Grid >
);
};
Expand code
Without columns or areas, Grid has one column that grows with its content. Pass columns={1}
when long content should wrap inside the grid instead of widening it.
Pass a CSS repeat(auto-fit, …) value when the column count should follow the available width. Wrap
the minimum column size in min(…, 100%) so a parent narrower than the minimum does not overflow.
First
Second
Third
Fourth
Fifth
Sixth
import { Grid } from '@luke-ui/react/grid' ;
import { ExampleItem } from '#docs' ;
export default () => {
return (
< Grid columns = "repeat(auto-fit, minmax(min(12rem, 100%), 1fr))" gap = "space.12" >
< ExampleItem >First</ ExampleItem >
< ExampleItem >Second</ ExampleItem >
< ExampleItem >Third</ ExampleItem >
< ExampleItem >Fourth</ ExampleItem >
< ExampleItem >Fifth</ ExampleItem >
< ExampleItem >Sixth</ ExampleItem >
</ Grid >
);
};
Expand code
columns and rows also accept a CSS value such as "1fr 1fr". areas takes one string per row.
Name each cell, use . for an empty cell, and place a child in an area with the area prop of
GridItem .
Without columns, columns from areas size to their content. Each named area must form one filled
rectangle.
Grid: Tracks and named areas
import { Grid, GridItem } from '@luke-ui/react/grid' ;
import { ExampleItem } from '#docs' ;
export default () => {
return (
< Grid
areas ={ [ 'a a' , 'b c' , 'd d' ] }
columns = "1fr 1fr"
gap = "space.12"
rows = "auto 1fr auto"
style ={ { minBlockSize: '16rem' } }
>
< GridItem area = "a" >
< ExampleItem >Area A</ ExampleItem >
</ GridItem >
< GridItem area = "b" renderRoot ={ ( domProps ) => < ExampleItem {... domProps } /> } >
Area B
</ GridItem >
< GridItem area = "c" renderRoot ={ ( domProps ) => < ExampleItem {... domProps } /> } >
Area C
</ GridItem >
< GridItem area = "d" >
< ExampleItem >Area D</ ExampleItem >
</ GridItem >
</ Grid >
);
};
Expand code
columns, rows, and areas accept a responsive object with a required initial value. Each
columns breakpoint can be a number or a CSS value. Stack named areas in one column at initial,
then arrange them from a wider breakpoint.
import { Grid, GridItem } from '@luke-ui/react/grid' ;
import { ExampleItem } from '#docs' ;
export default () => {
return (
< Grid
areas ={ { initial: [ 'a' , 'b' , 'c' ], bp768: [ 'a b b' , 'a c c' ] } }
columns ={ { initial: 1 , bp768: '10rem 1fr 1fr' } }
gap = "space.12"
>
< GridItem area = "a" renderRoot ={ ( domProps ) => < ExampleItem {... domProps } /> } >
Area A
</ GridItem >
< GridItem area = "b" >
< ExampleItem >Area B</ ExampleItem >
</ GridItem >
< GridItem area = "c" >
< ExampleItem >Area C</ ExampleItem >
</ GridItem >
</ Grid >
);
};
Expand code
GridItem places one child in its parent Grid and does nothing else. It renders a div and accepts
area, column, row, and the root props children, className, style, ref, elementType,
and renderRoot. The element form also accepts standard DOM attributes such as id, aria-*, and
data-*. It accepts className and style, but not Luke UI styling utilities. Use
renderRoot to style it with a layout component.
area takes the name of an area from the parent's areas. The value is a plain string, so a name
the parent does not define compiles. An unmatched name can create implicit grid tracks. The type
does not check it against areas.
column and row take a line placement: auto, a line number such as "2", a span such as
"span 2", a start and end such as "2 / 4", or a start and a span such as "1 / span 2".
Negative lines count from the end, so "1 / -1" covers every explicit column. The types use
${number}, which accepts any numeric string. It does not check for an integer or a valid track.
Pass named lines and other complex placements through className.
All three props accept a responsive object.
Use column="span 2" when an item should cover more than one column.
When columns is a number, keep each span within the active column count at every breakpoint. A
span that fits at bp768 can overflow a smaller initial column count, so change both values
together.
import { Grid, GridItem } from '@luke-ui/react/grid' ;
import { ExampleItem } from '#docs' ;
export default () => {
return (
< Grid columns ={ 2 } gap = "space.12" >
< GridItem column = "span 2" >
< ExampleItem >Spans two columns</ ExampleItem >
</ GridItem >
< ExampleItem >Second</ ExampleItem >
< ExampleItem >Third</ ExampleItem >
</ Grid >
);
};
Expand code
Place an item between grid lines with column and row. Each item in the example has a placement,
and the sidebar spans two rows.
import { Grid, GridItem } from '@luke-ui/react/grid' ;
import { ExampleItem } from '#docs' ;
export default () => {
return (
< Grid columns ={ 4 } gap = "space.12" >
< GridItem column = "1 / -1" >
< ExampleItem >Header</ ExampleItem >
</ GridItem >
< GridItem
column = "1"
renderRoot ={ ( domProps ) => < ExampleItem {... domProps } /> }
row = "2 / span 2"
>
Sidebar
</ GridItem >
< GridItem column = "2 / 5" >
< ExampleItem >Main</ ExampleItem >
</ GridItem >
< GridItem column = "2 / 5" >
< ExampleItem >Footer</ ExampleItem >
</ GridItem >
</ Grid >
);
};
Expand code
Pass renderRoot to render a Box or another layout component as the item.
The callback receives the resolved children, className, style, and ref. Spread them onto the
element you return, and the grid item is that element, with no extra wrapper. Put DOM attributes on
the returned element.
import { Box } from '@luke-ui/react/box' ;
import { Grid, GridItem } from '@luke-ui/react/grid' ;
import { ExampleItem } from '#docs' ;
export default () => {
return (
< Grid columns ={ 3 } gap = "space.12" >
< GridItem
column = "span 2"
renderRoot ={ ( domProps ) => (
< Box
{... domProps }
backgroundColor = "info.subtle"
borderRadius = "detail"
padding = "space.16"
/>
) }
>
Featured
</ GridItem >
< ExampleItem >Second</ ExampleItem >
< ExampleItem >Third</ ExampleItem >
</ Grid >
);
};
Expand code
Read Box for the renderRoot contract.
elementType and renderRoot are mutually exclusive.
Return a Stack, a Grid, or any other layout component from renderRoot to lay out the contents
of a grid item. The returned component is the item, so it takes part in the parent grid and lays out
its own children.
import { Grid, GridItem } from '@luke-ui/react/grid' ;
import { Stack } from '@luke-ui/react/stack' ;
import { ExampleItem } from '#docs' ;
export default () => {
return (
< Grid columns ={ 2 } gap = "space.12" >
< GridItem column = "span 2" renderRoot ={ ( domProps ) => < Stack {... domProps } gap = "space.8" /> } >
< ExampleItem >First</ ExampleItem >
< ExampleItem >Second</ ExampleItem >
</ GridItem >
< GridItem
column = "span 2"
renderRoot ={ ( domProps ) => < Grid {... domProps } columns ={ 2 } gap = "space.8" /> }
>
< ExampleItem >Third</ ExampleItem >
< ExampleItem >Fourth</ ExampleItem >
</ GridItem >
</ Grid >
);
};
Expand code
alignItems and justifyItems place each child within its grid area. alignContent and
justifyContent distribute the tracks when the grid is larger than its tracks.
import { Grid } from '@luke-ui/react/grid' ;
import { ExampleItem } from '#docs' ;
export default () => {
return (
< Grid alignItems = "end" columns ={ 2 } gap = "space.12" justifyItems = "center" >
< ExampleItem >Short</ ExampleItem >
< ExampleItem >
Two
< br />
lines
</ ExampleItem >
</ Grid >
);
};
Expand code
Grid uses
Box's elementType and renderRoot contract .
import { Grid } from '@luke-ui/react/grid' ;
import { ExampleItem } from '#docs' ;
const plainListStyle = { listStyle: 'none' } as const ;
export default () => {
return (
< Grid columns ={ 2 } elementType = "ul" gap = "space.12" margin = "0" padding = "0" style ={ plainListStyle } >
< ExampleItem elementType = "li" >First</ ExampleItem >
< ExampleItem elementType = "li" >Second</ ExampleItem >
< ExampleItem elementType = "li" >Third</ ExampleItem >
< ExampleItem elementType = "li" >Fourth</ ExampleItem >
</ Grid >
);
};
Expand code
Grid placement changes visual position only. Reading order and focus order follow the DOM order.
This applies to area, column, and row. Arrange areas and placements so the visual order
matches the DOM order at every breakpoint.
GridProps also accepts compatible DOM and ARIA attributes and event handlers for its rendered element.
Name Type Default alignContent
GridAlignmentProp <'alignContent' >Default: — Distribution of row tracks within the grid on the block axis.
alignItems
GridAlignmentProp <'alignItems' >Default: — Alignment of each child within its grid area on the block axis.
alignSelf
ResponsiveValue <"auto"
| "baseline"
| "center"
| "flex-end"
| "flex-start"
| "normal"
| "stretch" > | undefined Default: — areas
RequiredInitialResponsiveValue <ReadonlyArray <string >>Default: — Named grid areas, one string per row, such as ['a a', 'b c'].
Each row needs the same number of cells, and each named area must form a filled rectangle. Use
. for an empty cell. Accepts a responsive object with a required initial value.
blockSize
ResponsiveValue <"0"
| "100%"
| "auto"
| "fit-content"
| "max-content"
| "min-content" > | undefined Default: — borderBlockEndWidth
ResponsiveValue <"none"
| "thick"
| "thin" > | undefined Default: — borderBlockStartWidth
ResponsiveValue <"none"
| "thick"
| "thin" > | undefined Default: — borderInlineEndWidth
ResponsiveValue <"none"
| "thick"
| "thin" > | undefined Default: — borderInlineStartWidth
ResponsiveValue <"none"
| "thick"
| "thin" > | undefined Default: — columnGap
RequiredInitialResponsive <SprinklesProps['gap'] >Default: — Space between column tracks. Overrides gap on the inline axis.
columns
RequiredInitialResponsiveValue <number | string >Default: — Column tracks.
A positive integer creates that many equal columns that can shrink below their content width.
A non-empty string is used as grid-template-columns. Accepts a responsive object with a
required initial value, and each breakpoint can use either form.
flexBasis
ResponsiveValue <"0"
| "100%"
| "auto"
| "content"
| "fit-content"
| "max-content"
| "min-content" > | undefined Default: — flexGrow
ResponsiveValue <"0" | "1" > | undefined Default: — flexShrink
ResponsiveValue <"0" | "1" > | undefined Default: — gap
RequiredInitialResponsive <SprinklesProps['gap'] >Default: — Space between grid tracks.
inlineSize
ResponsiveValue <"0"
| "100%"
| "auto"
| "fit-content"
| "max-content"
| "min-content" > | undefined Default: — inset
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — insetBlock
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — insetBlockEnd
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — insetBlockStart
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — insetInline
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — insetInlineEnd
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — insetInlineStart
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — justifyContent
GridAlignmentProp <'justifyContent' >Default: — Distribution of column tracks within the grid on the inline axis.
justifyItems
ResponsiveValue <"baseline"
| "center"
| "end"
| "normal"
| "start"
| "stretch" > | undefined Default: — Alignment of each child within its grid area on the inline axis.
justifySelf
ResponsiveValue <"auto"
| "center"
| "end"
| "normal"
| "start"
| "stretch" > | undefined Default: — margin
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — marginBlock
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — marginBlockEnd
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — marginBlockStart
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — marginInline
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — marginInlineEnd
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — marginInlineStart
ResponsiveValue <"0"
| "auto"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — maxBlockSize
ResponsiveValue <"0"
| "100%"
| "fit-content"
| "max-content"
| "min-content"
| "none" > | undefined Default: — maxInlineSize
ResponsiveValue <"0"
| "100%"
| "container.448"
| "container.672"
| "container.896"
| "container.1152"
| "container.1280"
| "fit-content"
| "max-content"
| "min-content"
| "none" > | undefined Default: — minBlockSize
ResponsiveValue <"0"
| "100%"
| "auto"
| "fit-content"
| "max-content"
| "min-content" > | undefined Default: — minInlineSize
ResponsiveValue <"0"
| "100%"
| "auto"
| "fit-content"
| "max-content"
| "min-content" > | undefined Default: — order
ResponsiveValue <number > | undefined Default: — overflow
ResponsiveValue <"auto"
| "clip"
| "hidden"
| "scroll"
| "visible" > | undefined Default: — overflowX
ResponsiveValue <"auto"
| "clip"
| "hidden"
| "scroll"
| "visible" > | undefined Default: — overflowY
ResponsiveValue <"auto"
| "clip"
| "hidden"
| "scroll"
| "visible" > | undefined Default: — overscrollBehavior
ResponsiveValue <"auto" | "contain" > | undefined Default: — padding
ResponsiveValue <"0"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — paddingBlock
ResponsiveValue <"0"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — paddingBlockEnd
ResponsiveValue <"0"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — paddingBlockStart
ResponsiveValue <"0"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — paddingInline
ResponsiveValue <"0"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — paddingInlineEnd
ResponsiveValue <"0"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — paddingInlineStart
ResponsiveValue <"0"
| "space.4"
| "space.8"
| "space.12"
| "space.16"
| "space.24"
| "space.32"
| "space.40"
| "space.48"
| "space.64"
| "space.96" > | undefined Default: — placeSelf
ResponsiveValue <"auto"
| "center"
| "end"
| "normal"
| "start"
| "stretch" > | undefined Default: — position
ResponsiveValue <"absolute"
| "fixed"
| "relative"
| "static"
| "sticky" > | undefined Default: — rowGap
RequiredInitialResponsive <SprinklesProps['gap'] >Default: — Space between row tracks. Overrides gap on the block axis.
rows
RequiredInitialResponsiveValue <string >Default: — Row tracks, as a CSS track list such as "auto 1fr auto".
Accepts a responsive object with a required initial value.
Styling Advanced
GridItemProps also accepts compatible DOM and ARIA attributes and event handlers for its rendered element.
Name Type Default area
ResponsivePropValue <string >Default: — Name of the grid area to occupy. Pass one of the names in the parent Grid's areas.
The value is a plain string, so a name that the parent grid does not define compiles. Accepts a
responsive object.
column
ResponsivePropValue <GridItemPlacement >Default: — Column lines to occupy, such as "span 2" or "1 / -1". Named lines belong in className.
Accepts a responsive object.
row
ResponsivePropValue <GridItemPlacement >Default: — Row lines to occupy, such as "span 2" or "1 / 3". Named lines belong in className.
Accepts a responsive object.
Styling Advanced