Skip to content
LayoutGenerated from the public API

Grid

A responsive grid where the column count is a decision, not a class soup.

@luc/ui/layout

Examples

Column counts

The column count is a prop, and the breakpoint stack behind it is the component's decision — each count collapses one step before it has to.

columns=2

Return

Volatility

columns=3

Return

Volatility

Sharpe

columns=4

Return

Volatility

Sharpe

Drawdown

columns=6

Return

Volatility

Sharpe

Drawdown

Exposure

Turnover

Gap scale

One scale, shared with `Stack` and `Inline`, so a page cannot end up with four different ideas of what a gap is.

gap=sm

Return

Volatility

Sharpe

gap=md

Return

Volatility

Sharpe

gap=lg

Return

Volatility

Sharpe

gap=xl

Return

Volatility

Sharpe

Auto-fit tracks

`minItemWidth` is the other way to decide a grid: instead of a column count, a minimum cell width, and the browser fits as many as will go. Narrow the window and the count changes on its own.

minItemWidth=sm

Return

Volatility

Sharpe

Drawdown

Exposure

Turnover

minItemWidth=md

Return

Volatility

Sharpe

Drawdown

Exposure

Turnover

minItemWidth=lg

Return

Volatility

Sharpe

Drawdown

Exposure

Turnover

A cell that spans

A grid has no span prop, and it does not need one: a cell is an ordinary element, so `sm:col-span-2` on the thing inside it is the whole mechanism.

Risk report

Three of four columns

One column

A card wall

The composition the component exists for: equal cards, one gap, and a cell that grows with its own content instead of a fixed height.

Momentum

12-1 total return

+4.8%

Value

Book to price

-1.2%

Quality

Gross profitability

+0.9%

Usage

import { Grid } from "@luc/ui/layout";
<Grid columns={3} gap="md">
  {items.map((item) => <Card key={item.id} … />)}
</Grid>

`columns` fixes the count, `minItemWidth` fits as many as will go; `gap` is the same scale `Stack` and `Inline` use.

Package setup — peer requirements, the stylesheet and the provider — is on installation.

API

Read from the published TypeScript API, so a prop that is not listed here does not exist and a default that is listed is the one the compiler sees.

Exported symbols
ExportKindSignature
Grid3 documented props({ className, columns, minItemWidth, gap, ...props }: GridProps) => import("@types/react").JSX.Element

Grid props

Type: GridProps

Values the compiler reads from the declaration.

Grid props
PropTypeDefaultNotes
columns?Columns | undefined—
gap?Gap | undefined—
minItemWidth?"none" | "sm" | "md" | "lg" | "xl" | undefined—Auto-fit track sizing. Overrides `columns` when set.

Guidelines

Do

  • Reach for `columns` when the number is known and stable — a four-metric summary — and `minItemWidth` when it is not, such as a filter result or a card catalogue.
  • Keep the grid's gap on the same scale as the `Stack` around it: the two scales are one scale, and mixing them looks hand-built.
  • Give a cell its own span with a class on the child (`sm:col-span-2`); the grid deliberately has no span prop.

Don't

  • Do not lay a two-column form out with a grid: `FieldGroup` already does that, with the labels and the error messages in the right order.
  • Do not set a fixed height on a cell to make a row line up — let the tallest cell define the row.
  • Do not use `columns={6}` near a phone: every count collapses on the way down, and six columns at 390px is unreadable.

Accessibility

CSS Grid on a `div`: no semantics and no keyboard behaviour, so the reading order is the source order — which is why a wall of cards has to be written in the order a screen reader should read it. Nothing here is tabular; data that is a table belongs in `DataTable`, which renders real table markup with scoped headers.

Family

Layout

Space, rhythm and the surfaces a page is made of.

10 documented entries in this family. Open the family index

Luc UI v1.0Griddark theme