Grid
Apply the grid patch to any block element to lay out its children as a CSS grid with a column template and spacing between cells — the general-purpose primitive for card, property, and stat grids, instead of hand-rolling display: grid; gridTemplateColumns: ...; gap: .... Mirrors row's contract. Styles the host only; pair it with panelSection for padding or stack for a nested vertical group.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | number | string | 1 | Column count (expanded to repeat(N, minmax(0, 1fr))) or a raw grid-template-columns value. |
gap | number | 4 | Spacing multiplier for gap between cells. Final gap = themeSpacing(density × gap); at default density (1.5), gap 4 ≈ 1.5em. |
align | "flex-start" | "center" | "flex-end" | "stretch" | "baseline" | unset | Block-axis alignment of items (alignItems). Left unset by default. |
Example
import { grid } from "@domphy/ui";
const Cards = {
div: [{ div: "A" }, { div: "B" }],
$: [grid({ columns: 2 })],
};A raw template is accepted as columns when equal tracks are not enough:
{
div: [...],
$: [grid({ columns: "repeat(auto-fill, minmax(12em, 1fr))", gap: 6 })],
}Customization
Must see the source of patch at the bottom of each patch page to understand the structure then code it still code as html native element.
There are four levels of customization, in increasing order of effort:
- Patch props. Each patch exposes a small, stable set of props—typically fewer than five. Lowest friction.
- Context attributes. Use
dataTone,dataSize, anddataDensityon a container to shift tone, size, or density for an entire subtree without touching individual elements. - Inline override. Native-wins merge strategy: any property set directly on the element overrides the patch value.
- Create a variant. Clone a similar patch and edit it. Use this only when you need a reusable custom version.
Formulas
Unit - U = fontSize / 4 - convert final values with themeSpacing(n).
Size - n = intrinsic text lines, w = wrapping level, d = density factor:
height = (n * 6 + 2 * d * w) * U
paddingBlock = d * w * U
paddingInline = ceil(3 / w) * d * w * U
radius = d * w * UBase density d = 1.5:
| U | w=0 | w=1 | w=2 | w=3 |
|---|---|---|---|---|
height (n = 1) | 6 | 9 | 12 | 15 |
| paddingBlock | 0 | 1.5 | 3 | 4.5 |
| paddingInline | 3 | 4.5 | 6 | 4.5 |
| radius | 0 | 1.5 | 3 | 4.5 |
Tone - K = N / 2 where N is the palette length. For N = 18, K = 9.
| Role | Shift | n=0 |
|---|---|---|
| Background | parent +/- n | 0 |
| Text | bg + K | 6 |
| Border | bg + K/2 | 3 |
| Hover | bg + 2K/3 | 4 |
| Selected / Focus | above +/- K/3 | 2-4 |
State shift range: K/3 <= delta <= 2K/3.
import type { PartialElement } from "@domphy/core";
import { themeDensity, themeSpacing } from "@domphy/theme";
import type { FlexAlign } from "./stack.js";
/**
* A CSS grid with a column template and spacing between cells — the
* general-purpose primitive for card/property/stat grids instead of
* hand-rolling `display: "grid"; gridTemplateColumns: ...; gap: ...`.
* Mirrors `row()`'s contract. Styles the host only; apply to any block
* element.
*
* @param props.columns - Column count (expanded to `repeat(N, minmax(0, 1fr))`)
* or a raw `grid-template-columns` value. Defaults to `1`.
* @param props.gap - Spacing multiplier for gap between cells (default 4 = 1em at density 1).
* @param props.align - Block-axis alignment of items (`alignItems`). Unset by default.
* @example { div: [{ div: "A" }, { div: "B" }], $: [grid({ columns: 2 })] }
* @example { div: [...], $: [grid({ columns: "repeat(auto-fill, minmax(12em, 1fr))", gap: 6 })] }
*/
function grid(
props: { columns?: number | string; gap?: number; align?: FlexAlign } = {},
): PartialElement {
const { columns = 1, gap = 4, align } = props;
return {
style: {
display: "grid",
gridTemplateColumns:
typeof columns === "number"
? `repeat(${columns}, minmax(0, 1fr))`
: columns,
gap: (listener) => themeSpacing(themeDensity(listener) * gap),
...(align ? { alignItems: align } : {}),
},
};
}
export { grid };