Skip to content
6

Stat Card

Compact metric card with label, value, and an up/down/flat trend chip. Compound and single-prop APIs.

Example

Installation

npx shadcn@latest add https://hirael.com/r/stat-card.json

Usage

import {
  StatCard,
  StatCardLabel,
  StatCardValue,
  StatCardDelta,
} from "@/components/stat-card"

Paths assume the default @/ alias from your components.json. The example above shows the parts composed.

API

<StatCard />

+ native element props

No props of its own; forwards everything to the underlying element.

<StatCardLabel />

+ native element props

No props of its own; forwards everything to the underlying element.

<StatCardValue />

+ native element props

No props of its own; forwards everything to the underlying element.

<StatCardDelta />

+ native element props
PropTypeDefault
trend*StatCardTrendnone
childrenReact.ReactNodenone

Component source

'use client';

import * as React from 'react';
import { Minus, TrendingDown, TrendingUp } from 'lucide-react';

import { cn } from '@/lib/utils';

export type StatCardTrend = 'up' | 'down' | 'flat';

type StatCardProps = React.ComponentProps<'div'>;

const StatCard = ({ className, ...props }: StatCardProps) => {
  return (
    <div
      data-slot="stat-card"
      className={cn('flex flex-col gap-2 rounded-md border border-border bg-card p-5 text-card-foreground', className)}
      {...props}
    />
  );
};

type StatCardLabelProps = React.ComponentProps<'p'>;

const StatCardLabel = ({ className, ...props }: StatCardLabelProps) => {
  return (
    <p
      data-slot="stat-card-label"
      className={cn('font-mono text-[10px] uppercase tracking-[0.12em] text-muted-foreground', className)}
      {...props}
    />
  );
};

type StatCardValueProps = React.ComponentProps<'p'>;

const StatCardValue = ({ className, ...props }: StatCardValueProps) => {
  return (
    <p
      data-slot="stat-card-value"
      className={cn('text-3xl font-semibold tracking-[-0.035em] text-foreground', className)}
      {...props}
    />
  );
};

interface StatCardDeltaProps extends Omit<React.ComponentProps<'span'>, 'children'> {
  trend: StatCardTrend;
  children?: React.ReactNode;
}

const StatCardDelta = ({ trend, className, children, ...props }: StatCardDeltaProps) => {
  const Icon = trend === 'up' ? TrendingUp : trend === 'down' ? TrendingDown : Minus;
  const tone = trend === 'flat' ? 'text-muted-foreground' : 'text-foreground';
  return (
    <span
      data-slot="stat-card-delta"
      data-trend={trend}
      className={cn(
        'inline-flex w-fit items-center gap-1 rounded-sm bg-accent px-1.5 py-0.5 font-mono text-[11px] leading-none',
        tone,
        className,
      )}
      {...props}
    >
      <Icon className="size-3" aria-hidden />
      {children}
    </span>
  );
};

export { StatCard, StatCardLabel, StatCardValue, StatCardDelta };

Dependencies

npm

lucide-react