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:

Revenue
Orders
Conversion
Traffic
AOV
Refunds
<!-- 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.

Feature A Spans 2 columns — hero placement
Feature B Side highlight
Feature C
Feature D Spans 2 columns
<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.

Chart (8 cols)
Sidebar (4 cols)
Stat 1
Stat 2
Stat 3
Stat 4

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 layouts
  • cols={3} — dashboard cards and feature sections
  • cols={4} — stats cards and ecommerce metrics
  • cols={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-* or md: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 smCols and mdCols.
  • Choose column counts based on content density, not decoration — 4 skinny cards look worse than 3 well-spaced ones.
  • Use gap props 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 gap props 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 + cols together for a smooth responsive progression. The default grid-cols-1 on 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-4 on one grid, gap-6 on another, and gap-3 on 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), and lg (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-4 with gap-8 looks 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/react or @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
  • 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

Use the canonical Grid HTML classes and data attributes shown in the examples on this page. React and Vue adapters expose the same visual contract through framework-native props and events where the package implements an adapter.

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