Skip to content

FreeIn reviewv1.0.0

Stat Cards

Headline number cards with a change and a sparkline in the accent.
npx shadcn@latest add @vibebox/stat-cards

Controls

<StatCards />

About

Numbers first. The sparkline is a path computed from the trend; it does not scale text, and it is hidden from assistive technology because the value and change already say it.

Use it when

  • A dashboard opens on three to four key numbers.

Skip it when

  • You need an interactive chart: use Area Chart.

Install

  1. 1Add the VibeBox registry to components.json:
    {
      "registries": {
        "@vibebox": "https://motion.vibeboxph.com/r/{name}.json"
      }
    }
  2. 2Add the component with the shadcn CLI:
    npx shadcn@latest add @vibebox/stat-cards
  3. 3Use it:
    import { StatCards } from "@/components/vibebox/stat-cards";
    
    <StatCards accent="#7c5cff" />

AI prompt

Everything an AI coding tool needs to rebuild this component the way it looks here: colours, fonts, the art it draws, props and rules.

Read the prompt
Build the VibeBox Motion component "Stat Cards" (Data) in a Next.js App Router project with Tailwind CSS v4.

What it is
- Headline number cards with a change and a sparkline in the accent.
- A row of stat cards for a dashboard: label, a large tabular value, the change since last time and a small sparkline drawn as SVG in the accent colour with a soft fill. A description list, so the label and value are paired for assistive technology.

Install
- `npx shadcn@latest add @vibebox/stat-cards`
- Registry: add `"@vibebox": "https://motion.vibeboxph.com/r/{name}.json"` to components.json, then run the command. The source lands in `components/vibebox/stat-cards` and is yours to edit.

Visual spec
- Colours (the VibeBox spectrum, the same in light and dark):
    - --spectrum-1: #00c5fc (cyan)
    - --spectrum-2: #1d6ef0 (blue)
    - --spectrum-3: #5225ed (indigo)
    - --spectrum-4: #e434dc (magenta)
    - --spectrum-5: #fd3aa9 (pink)
    - --spectrum-6: #f98472 (coral)
    - --spectrum-7: #fcbe72 (amber)
- Ink surface (dark): background #05070c, card #0a0d15, text #f5f6fa, muted text #a3abbd, border rgba(255,255,255,0.08).
- Paper surface (light): background #f3f0ea, card #fbfaf7, text #0c0e14, muted text #4a4f5c, border rgba(12,14,20,0.12).
- Fonts:
    - Display and body: Figtree (400, 500, 600, 700), falling back to ui-sans-serif, system-ui.
    - Emphasis: Fraunces italic, for one or two words of a heading.
    - Labels and code: JetBrains Mono (400, 500), uppercase labels with 0.14em tracking.
- Shape: radius 8 to 12px on cards and panels; pills may be fully round. Hairline borders, soft glow instead of heavy shadow.
- Motion: animate transform and opacity only; fast ease-out (cubic-bezier(0.16, 1, 0.3, 1)), 140ms for micro-interactions, 320 to 520ms for reveals.

Art and media
- Built from HTML, CSS and inline SVG only; no image files or video.

Props
- `stats`: `{ label: string; value: string; delta?: string; trend?: number[] }[]`. The numbers: label, value, change and an optional trend.
- `accent`: `string` (default "blue"). The accent colour: blue, violet, emerald, amber, rose, or any CSS colour. It sets --app-accent on the root, so a parent can set it once for a whole screen.
- `className`: `string`. Merged with cn(); give it a width.

Behaviour and access
- Reduced motion: Nothing animates on its own.
- Keyboard: Every control is a native element in reading order.
- Screen readers: Semantic elements with accessible names; decorative marks are hidden.
- Touch: Targets are 36 px or larger; nothing depends on hover.
- Budget: about 0 KB of JavaScript, WebGL none, GPU none. It pauses while off screen.

Theming
Everything reads `--app-accent` (set by the `accent` prop, or by a parent) and the mode's tokens, so light and dark and any brand colour work without code changes. Pass a named accent or any CSS colour; Launchpad sets it once per app from the client's theme.

Usage
```tsx
import { StatCards } from "@/components/vibebox/stat-cards";

<StatCards accent="#7c5cff" />
```

Notes
Add the VibeBox Motion Stat Cards with `npx shadcn@latest add @vibebox/stat-cards`. Pass your numbers as formatted strings; the component does no formatting. Set the brand colour once with `--app-accent` on a parent (or the `accent` prop). It follows light and dark through the tokens; keep the licence header.

Rules
- Keep the licence header on every installed file.
- Original code only: do not copy components from other libraries, and do not add GSAP.
- Use tokens for colour, type and radius; no hard-coded brand values.
- Server Components by default; `"use client"` only for the island.

Code

1 files
components/vibebox/stat-cards/index.tsx
/**
 * VibeBox Motion · Stat Cards
 * Copyright (c) 2026 VibeBox. Licensed under the VibeBox Motion Free License:
 * https://motion.vibeboxph.com/license
 * Use it in unlimited personal, commercial and client projects.
 * Do not sell or redistribute it as a component, kit, template or builder.
 */
import { cn } from "@/lib/utils";
import { accentStyle } from "@/lib/vibebox/app-accent";

export type Stat = { label: string; value: string; delta?: string; trend?: number[] };
export type StatCardsProps = { stats?: Stat[]; accent?: string; className?: string };

const SAMPLE: Stat[] = [
  { label: "Bookings", value: "128", delta: "+12%", trend: [4, 6, 5, 8, 7, 10, 12] },
  { label: "Revenue", value: "₱84.2k", delta: "+6%", trend: [8, 7, 9, 8, 11, 10, 12] },
  { label: "No-shows", value: "3", delta: "-2", trend: [9, 7, 8, 5, 6, 4, 3] },
];

function Spark({ points }: { points: number[] }) {
  const max = Math.max(...points);
  const min = Math.min(...points);
  const d = points.map((p, i) => `${i ? "L" : "M"}${(i / (points.length - 1)) * 100} ${24 - ((p - min) / (max - min || 1)) * 20 - 2}`).join(" ");
  return (
    <svg viewBox="0 0 100 24" aria-hidden="true" preserveAspectRatio="none" className="h-8 w-full text-[var(--app-accent)]">
      <path d={`${d} L100 24 L0 24 Z`} fill="currentColor" opacity="0.14" />
      <path d={d} fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" vectorEffect="non-scaling-stroke" />
    </svg>
  );
}

/** Headline numbers: a label, a value, a change and a sparkline in the accent. */
export function StatCards({ stats = SAMPLE, accent, className }: StatCardsProps) {
  return (
    <dl data-vb="stat-cards" style={accentStyle(accent)} className={cn("grid gap-3 sm:grid-cols-3", className)}>
      {stats.map((s) => (
        <div key={s.label} className="grid gap-1 rounded-xl border border-border bg-card p-4">
          <dt className="text-caption text-muted-foreground">{s.label}</dt>
          <dd className="flex items-baseline gap-2 text-[1.6rem] leading-none font-semibold tracking-tight tabular-nums">
            {s.value}
            {s.delta && <span className="text-caption font-medium text-[var(--app-accent)]">{s.delta}</span>}
          </dd>
          {s.trend && s.trend.length > 1 && <Spark points={s.trend} />}
        </div>
      ))}
    </dl>
  );
}

Props

PropTypeDefaultDescription
stats{ label: string; value: string; delta?: string; trend?: number[] }[]—The numbers: label, value, change and an optional trend.
accentstring"blue"The accent colour: blue, violet, emerald, amber, rose, or any CSS colour. It sets --app-accent on the root, so a parent can set it once for a whole screen.
classNamestring—Merged with cn(); give it a width.

Accessibility and motion

Keyboard
Every control is a native element in reading order.
Screen readers
Semantic elements with accessible names; decorative marks are hidden.
Touch
Targets are 36 px or larger; nothing depends on hover.
Reduced motion
Nothing animates on its own.

Edge cases and limits

  • A trend of all equal values draws a flat line.
  • A list of people with accent monograms, short activity sentences and times

    A list of who did what and when, with initials in the accent.

    Data · Server

  • A smooth rising area chart in a blue gradient with faint gridlines and month labels

    A smooth area chart in your accent with gridlines, a marked last point and axis labels, in plain SVG.

    Data · Server

  • A table of invoices with client, service, date, amount and a status pill

    A data table with a caption, aligned numbers and status pills, scrolling sideways inside its frame.

    Data · Server

↑ ↓ to move↵ to openesc to close