Grid
Two-dimensional layout system.
Overview
Grid is a responsive two-dimensional layout primitive that controls column counts at multiple breakpoints and consistent gap spacing between items. Use it to arrange cards, stats, widgets, forms, and content panels into structured page layouts.
Why this exists
Every product UI needs a way to arrange items in rows and columns. Writing raw Tailwind grid classes per-breakpoint is repetitive and error-prone. Grid wraps display: grid into a <div> with per-breakpoint column props (smCols, mdCols, cols) and a single gap prop — one clean tag instead of a string of responsive utilities.
Mental model
Think of Grid as a flexible grid sheet: you set how many columns it should show on small, medium, and large screens, and every child automatically snaps into position. The gap between cells is consistent on both axes — no separate margin or padding hacks.
When to use
- SaaS dashboard stat cards — rows of KPI metrics in 2–4 columns
- Admin overview pages — widget-based layouts with mixed column spans
- Ecommerce back-office KPI cards — revenue, orders, conversion in a compact grid
- ERP / POS shortcut tiles — grid of action tiles for quick navigation
- Settings sections — multi-column form layouts with structured group labels
- Reporting widgets — chart panels arranged in a dashboard grid
- Bento marketing sections — asymmetric feature grids with varied column spans
- Starter-kit layouts — Laravel, React, and Vue dashboards built on Grid + Card + Stack
When not to use
- Do not use Grid for one-dimensional layouts — use Stack for vertical columns or horizontal groups
- Do not force too many columns on mobile — start with 1 on small screens and scale up with
smCols/mdCols - Do not use 12 columns for simple card groups — 12 columns are for advanced dashboard composition, not 3-stat layouts
- Do not use
role="grid"— Grid is a visual layout primitive, not an interactive data grid; it should not add ARIA roles by default - Do not use Grid when Stack or Flex is enough — one-dimensional layouts do not need a two-dimensional primitive
Basic example
A three-column grid of six stat cards with standard gap spacing:
<!-- 1 col on mobile, 2 on tablet, 3 on desktop -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="rounded-lg border border-border bg-background p-4">Revenue</div>
<div class="rounded-lg border border-border bg-background p-4">Orders</div>
<div class="rounded-lg border border-border bg-background p-4">Conversion</div>
<div class="rounded-lg border border-border bg-background p-4">Traffic</div>
<div class="rounded-lg border border-border bg-background p-4">AOV</div>
<div class="rounded-lg border border-border bg-background p-4">Refunds</div>
</div>
Common Grid patterns
Dashboard stats grid
Four KPI cards on desktop, two on tablet, one on mobile. Best for SaaS metrics and admin overviews.
Revenue
$48,290
+12.5%
Orders
1,342
+8.2%
Conversion
3.24%
-0.4%
Traffic
24.1k
+18.3%
import { Grid } from '@byteion/react';
export default function DashboardStats() {
return (
<Grid smCols={2} mdCols={4} gap={4}>
<StatCard label="Revenue" value="$48,290" trend="+12.5%" />
<StatCard label="Orders" value="1,342" trend="+8.2%" />
<StatCard label="Conversion" value="3.24%" trend="-0.4%" />
<StatCard label="Traffic" value="24.1k" trend="+18.3%" />
</Grid>
);
}
Bento / feature grid
Asymmetric grid with mixed column spans for marketing landing sections. A hero feature spans two columns beside a secondary feature.
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="md:col-span-2 rounded-2xl bg-muted p-6">
Feature A (spans 2)
</div>
<div class="rounded-2xl bg-primary-50 p-6">
Feature B
</div>
<div class="rounded-2xl bg-muted p-6">
Feature C
</div>
<div class="md:col-span-2 rounded-2xl bg-muted p-6">
Feature D (spans 2)
</div>
</div>
12-column advanced layout
Use cols={12} for complex dashboard surfaces where widgets need precise column spans.
Responsive columns
Grid controls column counts per breakpoint through three props. Unspecified props inherit from the smaller breakpoint — start with 1 column on mobile and scale up.
| Prop | Breakpoint | Values | Default |
|---|---|---|---|
| cols | Large / desktop (lg:) |
1, 2, 3, 4, 5, 6, 12 | 3 |
| mdCols | Medium / tablet (md:) |
1, 2, 3, 4, 6 | — |
| smCols | Small / mobile (sm:) |
1, 2, 3, 4 | 1 |
| gap | All breakpoints | 2, 3, 4, 5, 6, 8 | 4 |
Common column combinations:
cols={2}— simple two-column forms or settings layoutscols={3}— dashboard cards and feature sectionscols={4}— stats cards and ecommerce metricscols={12}— advanced dashboard composition with mixed-span widgets
Gap scale
The gap prop applies consistent spacing between grid cells on both axes. Choose a single global value per section instead of mixing inline margin utilities.
| Value | Tailwind class | Use case |
|---|---|---|
| 4 | gap-4 | Compact dashboards — dense KPI cards and stat grids |
| 6 | gap-6 | Standard page sections — settings, panels, content grids |
| 8 | gap-8 | Spacious marketing or overview layouts — landing features, bento sections |
Anatomy
- Grid container —
<div class="grid">with per-breakpoint column utilities and a gap utility - Grid items — direct children that auto-place into the next available cell in source order
- Gap — consistent gutter spacing between all rows and columns via
gap-* - Col-span modifier — optional
col-span-*ormd:col-span-*utility class on individual items to override default placement
Usage guidelines
- Use semantic elements (
<section>,<article>,<nav>,<aside>,<ul>) as grid children when the content has semantic meaning — Grid is a visual primitive only. - Start with 1 column on mobile and scale up with
smColsandmdCols. - Choose column counts based on content density, not decoration — 4 skinny cards look worse than 3 well-spaced ones.
- Use
gapprops instead of hardcoded spacing utilities. - Use Card, StatCard, or Panel primitives inside Grid for consistent surfaces.
- Wrap the grid in Container for consistent page margins.
Do and Don't
Do
- Use Grid for two-dimensional page layouts
- Start with one column on small screens
- Choose columns based on content density, not decoration
- Use
gapprops instead of hardcoded spacing - Use Card, StatCard, or Panel inside Grid for consistent surfaces
- Use
col-span-*for emphasis on important content
Don't
- Use Grid when Stack or Flex is enough
- Force too many columns on mobile
- Use 12 columns for simple card groups
- Use
role="grid"for visual layout only - Hardcode inconsistent gap utilities across pages
- Use visual order (
order-*) that breaks reading order
Accessibility
Grid is a visual layout primitive — not an interactive data grid. It must not add ARIA roles by default.
- Do not use
role="grid"— that role is reserved for interactive widgets that require keyboard navigation (arrow keys, cell selection, row activation). Applying it to a static layout is a WCAG failure. - Use semantic elements — wrap grid items in
<section>,<article>,<ul>/<li>,<nav>, or<aside>when the content carries meaning. Grid provides the visual placement; semantics provide the meaning. - Maintain logical source order — screen readers and keyboard navigation follow DOM order. Use CSS Grid's visual reordering sparingly; never reorder interactive elements visually without matching the DOM sequence.
- The component renders a plain
<div>with no ARIA attributes. It does not interfere with assistive technology.
Customization
Grid outputs Tailwind grid utility classes. Override the column layout, gap, or item spans by passing additional Tailwind classes via className (React) or class (Vue / HTML). The component uses cn() to merge classes — your custom utilities take precedence.
For advanced layouts, apply col-span-*, row-span-*, or md:col-span-* directly on grid children. These are plain Tailwind utilities and require no component support.
HTML example
Sales
$12,340
Last 30 days
Subscribers
1,024
+12 new
Avg. Time
4m 32s
Per session
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="rounded-xl border border-border bg-background p-6 shadow-sm">
<h4 class="font-semibold text-foreground">Sales</h4>
<p class="text-2xl font-semibold mt-2">$12,340</p>
<p class="text-xs text-muted-foreground mt-1">Last 30 days</p>
</div>
<div class="rounded-xl border border-border bg-background p-6 shadow-sm">
<h4 class="font-semibold text-foreground">Subscribers</h4>
<p class="text-2xl font-semibold mt-2">1,024</p>
<p class="text-xs text-muted-foreground mt-1">+12 new</p>
</div>
<div class="rounded-xl border border-border bg-background p-6 shadow-sm">
<h4 class="font-semibold text-foreground">Avg. Time</h4>
<p class="text-2xl font-semibold mt-2">4m 32s</p>
<p class="text-xs text-muted-foreground mt-1">Per session</p>
</div>
</div>
React example
import { Grid } from '@byteion/react';
export default function StatsGrid() {
return (
<Grid smCols={2} lgCols={3} gap={6}>
<StatCard
label="Revenue"
value="$48,290"
trend="+12.5%"
trendDirection="up"
/>
<StatCard
label="Orders"
value="1,342"
trend="+8.2%"
trendDirection="up"
/>
<StatCard
label="Conversion Rate"
value="3.24%"
trend="-0.4%"
trendDirection="down"
/>
<StatCard
label="Active Users"
value="12.4k"
trend="+18.3%"
trendDirection="up"
/>
</Grid>
);
}
Vue example
<script setup lang="ts">
import { Grid } from '@byteion/vue';
import StatCard from '@/components/StatCard.vue';
</script>
<template>
<Grid :smCols="2" :lgCols="3" :gap="6">
<StatCard
label="Revenue"
value="$48,290"
trend="+12.5%"
trend-direction="up"
/>
<StatCard
label="Orders"
value="1,342"
trend="+8.2%"
trend-direction="up"
/>
<StatCard
label="Conversion Rate"
value="3.24%"
trend="-0.4%"
trend-direction="down"
/>
<StatCard
label="Active Users"
value="12.4k"
trend="+18.3%"
trend-direction="up"
/>
</Grid>
</template>
API Reference
React
<Grid> extends HTMLAttributes<HTMLDivElement> — all standard div attributes pass through.
| Prop | Type | Default |
|---|---|---|
| cols | 1 | 2 | 3 | 4 | 5 | 6 | 12 |
3 |
| smCols | 1 | 2 | 3 | 4 |
1 |
| mdCols | 1 | 2 | 3 | 4 | 6 |
— |
| gap | 2 | 3 | 4 | 5 | 6 | 8 |
4 |
Vue
<Grid> accepts the same props as the React version. All standard HTML attributes pass through.
| Prop | Type | Default |
|---|---|---|
| cols | 1 | 2 | 3 | 4 | 5 | 6 | 12 |
3 |
| smCols | 1 | 2 | 3 | 4 |
1 |
| mdCols | 1 | 2 | 3 | 4 | 6 |
— |
| gap | 2 | 3 | 4 | 5 | 6 | 8 |
4 |
Developer tips
- Use
smCols+mdCols+colstogether for a smooth responsive progression. The defaultgrid-cols-1on mobile prevents horizontal overflow before you add breakpoints. - Use
col-span-*for emphasis. Make important cards span 2 columns on larger screens — useful for hero stats, featured content, or full-width charts. - Combine with Container. Wrap the grid in Container for consistent page margins and maximum width.
- Nest Grid inside Section for vertical breathing room between page areas — Container → Section → Grid → Card creates a robust page structure.
- Use semantic items. Render
<article>or<li>as grid children when each cell is a standalone content unit.
Common mistakes
- Using Grid for one-dimensional vertical spacing — Grid creates both rows and columns. If you only need vertical stacking, use Stack or plain
space-y-*. - Too many mobile columns — content becomes unreadable when squeezed into 3+ columns on a 375px viewport. Always start with 1 on
sm. - Mixing random gap utilities — using
gap-4on one grid,gap-6on another, andgap-3on a third creates inconsistent visual rhythm. Define a gap scale per page or section. - Using visual order that breaks reading order — CSS Grid can reorder items visually, but screen readers follow DOM order. Never place interactive elements (buttons, links, inputs) in a different visual position than their DOM index.
- Using
role="grid"incorrectly —role="grid"is for interactive spreadsheet-like widgets (e.g., Airtable, Google Sheets). Adding it to a static card layout triggers screen readers to announce grid navigation mode and breaks accessibility. - Nesting Grids more than 2 levels deep — complex nested grids create confusing tab order and are hard to maintain. Flatten your layout or use Section boundaries.
Production usage tips
- Test mobile, tablet, and desktop breakpoints — verify the grid looks intentional at
sm(1 col),md(smCols), andlg(cols). Test portrait and landscape tablet orientations. - Keep DOM order logical — screen reader and keyboard tab order follows the DOM. If grid items contain interactive elements, ensure the visual layout does not reorder focus or reading flow.
- Align React / Vue props with core examples — the canonical HTML rendering is the source of truth. Ensure all three frameworks produce the same visual output for the same prop values.
- Use consistent gap values across dashboard modules — all grids on the same page should share the same gap value. Mixing
gap-4withgap-8looks disjointed. - Validate dark mode and branded themes — Grid itself uses no colour tokens, but its children do. Test Card, StatCard, and other primitives inside Grid under all themes.
- For Laravel / server-rendered apps — use the raw HTML structure shown in the HTML example. Grid is a zero-JS component.
- For React / Vue SPAs — pair Grid with Container, Section, and Stack for full page hierarchy. Import from
@byteion/reactor@byteion/vue.
Premium examples
Pro patterns available in Byteion Pro:
- Analytics dashboard grid with draggable widgets — users can reorder KPI cards and chart panels with drag-and-drop layout persistence
- ERP workspace grid with resizable panels — adjustable-width columns for order lists, inventory, and customer details in an ERP dashboard
- Ecommerce admin KPI grid with filters — date-range filter bar above a reconfigurable KPI grid that updates metrics on selection
- POS shortcut tile grid — categorical action tiles in a compact 4-column grid for quick product or transaction selection
- Bento landing page section — asymmetric marketing grid with mixed span layout, hover elevation, and CTA integration
Related components
- Container — page-level width and horizontal padding
- Stack — one-dimensional vertical or horizontal layout
- Section — vertical spacing between page areas
- Card — surface for grouping related content inside grid cells
API Reference
Related components
Pair this component with adjacent Byteion primitives from the same workflow: form controls for data entry, feedback components for validation, and layout primitives for spacing.
Runtime events
Byteion keeps framework APIs idiomatic: HTML uses DOM custom events, React uses callback props, and Vue uses emitted events / v-model updates.
HTML / JS events
No HTML runtime events are declared by this adapter.
React callbacks
No React callback events are declared by this adapter.
Vue emits
No Vue emitted events are declared by this adapter.
Remote / AJAX
This component does not implement Byteion JS remote loading. Use normal HTML form submission, framework state, or your application data layer around it.
Unlock Premium Patterns
Get access to copy-paste ready Pro blocks, SaaS templates, and advanced component patterns.
Explore Pro Components