Grid
A two-dimensional CSS grid primitive. Use it instead of an inline
display: grid — columns are an explicit count and gap is a
design token, so AI never has to guess a track template.
Fixed columns
A set number of equal-width columns with a token gap. No track template to hand-write, so AI cannot drift.
Revenue
$48.2k
Users
12,840
Orders
1,204
Refunds
32
Churn
2.1%
MRR
$9.6k
import { Grid, Card, CardBody, Text, Heading } from "@usevyre/react";
const stats = [
{ label: "Revenue", value: "$48.2k" },
{ label: "Users", value: "12,840" },
{ label: "Orders", value: "1,204" },
{ label: "Refunds", value: "32" },
{ label: "Churn", value: "2.1%" },
{ label: "MRR", value: "$9.6k" },
];
<Grid columns={3} gap="md">
{stats.map((s) => (
<Card key={s.label}>
<CardBody>
<Text size="sm" color="muted">{s.label}</Text>
<Heading size="lg">{s.value}</Heading>
</CardBody>
</Card>
))}
</Grid> <script setup>
import { Grid, Card, CardBody, Text, Heading } from "@usevyre/vue";
const stats = [
{ label: "Revenue", value: "$48.2k" },
{ label: "Users", value: "12,840" },
{ label: "Orders", value: "1,204" },
{ label: "Refunds", value: "32" },
{ label: "Churn", value: "2.1%" },
{ label: "MRR", value: "$9.6k" },
];
</script>
<template>
<Grid :columns="3" gap="md">
<Card v-for="s in stats" :key="s.label">
<CardBody>
<Text size="sm" color="muted">{{ s.label }}</Text>
<Heading size="lg">{{ s.value }}</Heading>
</CardBody>
</Card>
</Grid>
</template> Spanning cells with GridItem
Wrap a cell in <GridItem> to span columns/rows or pin it
to a specific grid line — instead of a nested div with an inline
grid-column.
Main content
Spans 2 of 3 columns
Sidebar
1 column
Footer A
Footer B
Footer C
import { Grid, GridItem, Card, CardBody, Text, Heading } from "@usevyre/react";
<Grid columns={3} gap="md">
<GridItem colSpan={2}>
<Card>
<CardBody>
<Heading size="sm">Main content</Heading>
<Text color="muted">Spans 2 of 3 columns</Text>
</CardBody>
</Card>
</GridItem>
<Card>
<CardBody>
<Heading size="sm">Sidebar</Heading>
<Text color="muted">1 column</Text>
</CardBody>
</Card>
<Card>
<CardBody><Text>Footer A</Text></CardBody>
</Card>
<Card>
<CardBody><Text>Footer B</Text></CardBody>
</Card>
<Card>
<CardBody><Text>Footer C</Text></CardBody>
</Card>
</Grid> <script setup>
import { Grid, GridItem, Card, CardBody, Text, Heading } from "@usevyre/vue";
</script>
<template>
<Grid :columns="3" gap="md">
<GridItem :col-span="2">
<Card>
<CardBody>
<Heading size="sm">Main content</Heading>
<Text color="muted">Spans 2 of 3 columns</Text>
</CardBody>
</Card>
</GridItem>
<Card>
<CardBody>
<Heading size="sm">Sidebar</Heading>
<Text color="muted">1 column</Text>
</CardBody>
</Card>
<Card>
<CardBody><Text>Footer A</Text></CardBody>
</Card>
<Card>
<CardBody><Text>Footer B</Text></CardBody>
</Card>
<Card>
<CardBody><Text>Footer C</Text></CardBody>
</Card>
</Grid>
</template> Responsive auto-fit
columns="auto-fit" fits as many columns as the container
width allows and wraps the rest — responsive with zero media queries.
Revenue
$48.2k
Users
12,840
Orders
1,204
Refunds
32
import { Grid, Card, CardBody, Text, Heading } from "@usevyre/react";
<Grid columns="auto-fit" gap="md">
{stats.slice(0, 4).map((s) => (
<Card key={s.label}>
<CardBody>
<Text size="sm" color="muted">{s.label}</Text>
<Heading size="lg">{s.value}</Heading>
</CardBody>
</Card>
))}
</Grid> <script setup>
import { Grid, Card, CardBody, Text, Heading } from "@usevyre/vue";
</script>
<template>
<Grid columns="auto-fit" gap="md">
<Card v-for="s in stats.slice(0, 4)" :key="s.label">
<CardBody>
<Text size="sm" color="muted">{{ s.label }}</Text>
<Heading size="lg">{{ s.value }}</Heading>
</CardBody>
</Card>
</Grid>
</template> Props
Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | number | "auto-fit" | 1 | Equal-width column count (1–12), or 'auto-fit' for responsive wrapping. |
rows | number | "auto" | — | Explicit row count, or 'auto'. |
flow | "row" | "column" | "dense" | "row-dense" | "column-dense" | — | grid-auto-flow. |
gap | "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "md" | Space between cells. Maps to a --vyre-spacing token. |
rowGap | "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | — | row-gap override (token). |
columnGap | "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | — | column-gap override (token). |
align | "start" | "center" | "end" | "stretch" | "stretch" | align-items. |
justify | "start" | "center" | "end" | "stretch" | — | justify-items. |
width | "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | — | Width — keyword (full=100%, fit, screen) or fixed-rem token size. |
height | "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | — | Height — keyword or fixed-rem token size. |
as | string | "div" | HTML tag to render. |
class | string | — | Additional CSS class. |
GridItem props
Props
| Prop | Type | Default | Description |
|---|---|---|---|
colSpan | number | — | Columns this item spans. |
rowSpan | number | — | Rows this item spans. |
colStart | number | — | 1-based column line to start at. |
rowStart | number | — | 1-based row line to start at. |
as | string | "div" | HTML tag to render. |
Valid props
| Prop | Values | Default |
|---|---|---|
flow | "row"|"column"|"dense"|"row-dense"|"column-dense" | — |
gap | "none"|"xs"|"sm"|"md"|"lg"|"xl"|"2xl" | md |
rowGap | "none"|"xs"|"sm"|"md"|"lg"|"xl"|"2xl" | — |
columnGap | "none"|"xs"|"sm"|"md"|"lg"|"xl"|"2xl" | — |
align | "start"|"center"|"end"|"stretch" | stretch |
justify | "start"|"center"|"end"|"stretch" | — |
width | "auto"|"full"|"fit"|"screen"|"xs"|"sm"|"md"|"lg"|"xl"|"2xl" | — |
height | "auto"|"full"|"fit"|"screen"|"xs"|"sm"|"md"|"lg"|"xl"|"2xl" | — |
Common AI mistakes
- <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr' }}>→ Use <Grid columns={3} gap="md">
- columns="3" (string)→ Use columns={3} or columns="auto-fit"
- Nested div with inline grid-column for spanning→ Wrap the cell in <GridItem colSpan={2}>
- style={{ width: "100%" }} / style={{ height: 320 }}→ Use the width / height prop: width="full", width="md", height="screen", etc.
Quick examples
Three-column grid with a wide first cell
<Grid columns={3} gap="lg">
<GridItem colSpan={2}><Card>Wide</Card></GridItem>
<Card>Two</Card>
<Card>Three</Card>
</Grid>Responsive auto-fit grid
<Grid columns="auto-fit" gap="md">
{items.map((i) => <Card key={i.id}>{i.title}</Card>)}
</Grid>