Build a Quick Stats Grid widget that arranges MetricCard components in a responsive grid with configurable column count. It complements the existing metric-card.tsx (individual cards) and kpi-summary-strip.tsx (horizontal strip) by providing a grid layout suitable for dashboard overviews, with loading states and realistic Storybook stories.
Introduction
Overview
The design system provides MetricCard for individual KPI display and KpiSummaryStrip for horizontal arrangements of 1-6 metrics. However, dashboards often need a grid layout with more than 6 metrics, configurable column counts, and loading states. KpiSummaryStrip is specifically designed for a horizontal strip and auto-sizes columns based on tile count (up to 6). A QuickStatsGrid widget provides a more flexible grid layout for arbitrary metric counts with explicit column control.
Goals
Provide a QuickStatsGrid widget that renders MetricCard components in a responsive CSS grid.
Support configurable column count (default auto-responsive) with explicit override.
Handle loading state with skeleton cards matching the expected card layout.
Ship with Storybook stories using realistic dashboard data.
Non-Goals
Replacing KpiSummaryStrip (it remains the right choice for horizontal 1-6 metric strips).
Chart/graph rendering within cards (MetricCard already supports sparklines).
Drag-to-rearrange card positions.
Scope
In Scope
Item
Description
QuickStatsGrid widget
CSS grid container for MetricCard components.
Column configuration
columns prop for explicit column count; responsive default (1→2→3→4 across breakpoints).
Loading state
Skeleton cards matching the expected grid layout.
MetricCard pass-through
Each stat config maps to MetricCard props (label, value, delta, sparkline, icon, tone).
Card variants
Support for MetricCard variant (default, outlined, filled) and tone applied uniformly or per card.
Stories with realistic data
Storybook stories demonstrating SaaS dashboard, e-commerce, and DevOps metric grids.
Unit tests
Tests for responsive breakpoint behavior, loading state rendering, and prop pass-through.
Out of Scope
Item
Reason
Chart integration
MetricCard already supports sparklines; complex charts belong in separate chart components.
Card reordering
Drag-and-drop is a separate concern with high complexity.
Server-side data fetching
Consumer provides the stat data; loading state is driven by consumer.
Animations between states
Cards transition via standard motion tokens; no complex enter/exit orchestration.
Users and Pain Points
User
Pain Point
Dashboard developers
Layout MetricCards manually with CSS grid for every dashboard; inconsistent responsive breakpoints.
Product designers
No standard grid layout for metric cards; designs specify grids that developers implement differently.
Developers building overview pages
KpiSummaryStrip caps at 6 tiles and is horizontal-strip only; no grid option for 8-12 metrics.
Definitions
Term
Definition
Stat
A single metric displayed in a MetricCard (label, value, delta, sparkline).
Column count
The number of MetricCards per row in the grid.
Responsive default
A grid that automatically adjusts column count based on viewport width.
Current State
MetricCard (src/components/ui/metric-card.tsx): Individual metric display with label, value, delta, deltaDirection, sparkline, icon, trend. Supports variant (default, outlined, filled) and tone (themedSurfaceToneClasses).
KpiSummaryStrip (src/components/widgets/kpi-summary-strip.tsx): Horizontal strip of 1-6 MetricCards with auto-responsive grid sizing. Accepts stats: KpiConfig[], variant. Limited to 6 tiles and horizontal layout.
No general-purpose metric grid exists for 6+ metrics or explicit column control.
A CSS grid container using Tailwind grid classes. The default responsive behavior:
Mobile (< 640px): 1 column
Small (640px+): 2 columns
Medium (768px+): 3 columns
Large (1024px+): 4 columns
The columns prop overrides this with an explicit column count at all breakpoints. A minCardWidth prop can alternatively set grid-template-columns: repeat(auto-fill, minmax(minCardWidth, 1fr)) for a fluid approach.
Stat Configuration
Reuse the KpiConfig interface from KpiSummaryStrip for consistency. Each stat maps directly to MetricCard props.
Loading State
When loading is true, render skeleton cards. The skeleton count matches either stats.length (if data has been loaded before) or a skeletonCount prop. Each skeleton card matches the MetricCard dimensions with shimmer animation.
Card Variant
variant and tone can be applied globally (all cards) or per-stat (each StatConfig can override).
Requirements
Requirement Priorities
Must Have: Grid layout with MetricCards, responsive default, loading state.
Should Have: Explicit column count, per-stat tone override, gap configuration.
Grid layout: Use Tailwind CSS grid classes. Default: grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4. If columns prop is set, use grid-cols-{columns} (or inline style for arbitrary values).
Card rendering: Map over stats array and render a MetricCard for each. Pass through label, value, delta, deltaDirection, description, sparkline, icon. Apply global variant and tone, then per-stat overrides.
Loading state: When loading is true, render skeletonCount skeleton cards. Use the existing Skeleton component with rounded-xl and matching MetricCard dimensions (h-[120px] or similar).
Click handler: If onCardClick is provided, wrap each MetricCard in a <button> or add onClick and tabIndex={0} for keyboard access.
Stories in src/components/widgets/quick-stats-grid.stories.tsx. Create realistic scenarios: