VisorVisor
ComponentsAdmin

Stat Card

Compact admin dashboard metric card with label, value, delta, trend, and footer slots. Built with CSS Modules, container queries, and accessible delta announcements — copy it into your project and own it completely.

npx visor add stat-card

Basic

Total Revenue

$48,120

With Delta (Up)

Total Revenue

$48,120

+12.4%vs last monthup vs last month

With Delta (Down)

Churn Rate

3.2%

-0.4%vs last monthdown vs last month

With Delta (Flat)

Signups

412

0%vs last monthflat vs last month

With Trend

Sessions

2,340

Variants

Variants control visual emphasis. Pair with any size.

Default

1,204

+4.1%up

Highlight

$48,120

+12.4%vs last monthup vs last month

Sizes

Dimensional density. md is the dashboard default; sm is for dense rows of compact cards where multiple metrics need to share a tight row.

Active Users

892

Sessions

2,340

+8%up

Signups

412

+2%up

Bounce

28%

-1%down

Revenue

$12k

+5%up

Installation

npx visor add stat-card

This copies two files into your project:

  • components/ui/stat-card/stat-card.tsx — the component
  • components/ui/stat-card/stat-card.module.css — the styles

Usage

import { StatCard } from '@/components/ui/stat-card/stat-card';

export default function Example() {
  return (
    <StatCard
      label="Total Revenue"
      value="$48,120"
      delta={{ value: '+12.4%', direction: 'up', label: 'vs last month' }}
    />
  );
}

API Reference

StatCardProps

PropTypeDefaultDescription
label*React.ReactNodeSmall uppercase label describing the metric.
value*React.ReactNodeProminent metric value rendered in a large display size.
deltaStatCardDeltaChange indicator with value, direction ("up" | "down" | "flat"), and optional context label. Direction is announced to screen readers.
trendReact.ReactNodeSlot for a sparkline, chart, or icon rendered next to the label. Marked aria-hidden by default.
footerReact.ReactNodeSublabel or link rendered beneath the value.
variant'default' | 'highlight''default'Visual emphasis. Highlight adds an accent-tinted surface, border, and glow.
size'sm' | 'md''md'Dimensional density. Use sm for dense rows of compact cards; md is the default dashboard size.
as'article' | 'section' | 'div''article'Root element tag. Defaults to article for landmark semantics.
classNamestringAdditional CSS class names to merge onto the root element.
...propsReact.HTMLAttributes<HTMLElement>All standard HTML attributes are forwarded to the root.

The component also accepts all standard HTML attributes for the root element (defaults to <article>).

StatCardDelta

FieldTypeDescription
valueReact.ReactNodeDisplay value, e.g. "+12.4%" or "-$2.1K".
direction'up' | 'down' | 'flat'Semantic direction — drives color and glyph.
labelstring (optional)Context label (e.g. "vs last month"). Visible and announced.

Accessibility

Color alone is never sufficient to convey the direction of a change. StatCard always announces the direction word (up, down, or flat) to screen readers via visually-hidden text alongside the visible glyph and delta value. The glyph itself is marked aria-hidden so assistive tech hears a clean sentence like "up 12.4% vs last month".

The root element defaults to <article>, giving screen reader users a landmark they can navigate to. Use the as prop to override this when embedding inside another landmark.

Source Files

After running npx visor add stat-card, you'll have:

stat-card.tsx

A forwardRef component using CVA for variant selection and CSS Modules for layout. The root element is configurable via the as prop.

stat-card.module.css

All styles use CSS custom properties from @loworbitstudio/visor-core, so the card automatically adapts to your active theme. The wrapper uses container-type: inline-size so the header row collapses on very narrow containers instead of overflowing. Transitions are wrapped in a prefers-reduced-motion guard.

Customization

After copying the component, you own it completely. Common customizations:

  • Replace the Unicode arrow glyphs with Phosphor icons (ArrowUp, ArrowDown, Minus).
  • Add a loading state that renders a skeleton value.
  • Extend variants with a subtle treatment for secondary dashboards.
  • Swap the <article> root for a <button> when the whole card should be clickable.