d-ui logod-ui
カード

Stats Card

数値・トレンド・アイコンを表示するダッシュボード向けカード。

インストール

npx shadcn add https://d-ui.daigo-suhara.com/registry/stats-card.json

サンプル

月間売上

¥1,234,567

+12.5%先月比

使い方

import { StatsCard } from "@/components/ui/stats-card";
import { Users } from "lucide-react";

export default function Example() {
  return (
    <StatsCard
      title="月間ユーザー数"
      value="12,540"
      trend={8.2}
      trendLabel="先月比"
      icon={<Users className="h-4 w-4" />}
    />
  );
}

プロパティ

title必須
string

カードのラベル

value必須
string | number

表示する値

trend必須
number

前期比(%)

trendLabel必須
string

トレンドの補足テキスト

icon必須
ReactNode

アイコン

prefix必須
string

値の前に付く文字

suffix必須
string

値の後に付く文字

ソースコード

import * as React from "react";
import { cn } from "@/lib/utils";
import { TrendingUp, TrendingDown, Minus } from "lucide-react";

interface StatsCardProps {
  title: string;
  value: string | number;
  trend?: number;
  trendLabel?: string;
  icon?: React.ReactNode;
  prefix?: string;
  suffix?: string;
  className?: string;
}

export function StatsCard({
  title,
  value,
  trend,
  trendLabel,
  icon,
  prefix,
  suffix,
  className,
}: StatsCardProps) {
  const trendDirection =
    trend == null ? null : trend > 0 ? "up" : trend < 0 ? "down" : "flat";

  return (
    <div
      className={cn(
        "rounded-xl border bg-card p-5 shadow-sm",
        className
      )}
    >
      <div className="flex items-start justify-between mb-3">
        <p className="text-sm text-muted-foreground font-medium">{title}</p>
        {icon && (
          <div className="flex h-9 w-9 items-center justify-center rounded-lg bg-primary/10 text-primary">
            {icon}
          </div>
        )}
      </div>

      <p className="text-3xl font-bold tracking-tight tabular-nums">
        {prefix}
        {value}
        {suffix}
      </p>

      {trend != null && (
        <div className="mt-2 flex items-center gap-1">
          {trendDirection === "up" && (
            <TrendingUp className="h-3.5 w-3.5 text-emerald-500" />
          )}
          {trendDirection === "down" && (
            <TrendingDown className="h-3.5 w-3.5 text-red-500" />
          )}
          {trendDirection === "flat" && (
            <Minus className="h-3.5 w-3.5 text-muted-foreground" />
          )}
          <span
            className={cn(
              "text-xs font-medium",
              trendDirection === "up" && "text-emerald-500",
              trendDirection === "down" && "text-red-500",
              trendDirection === "flat" && "text-muted-foreground"
            )}
          >
            {trend > 0 ? "+" : ""}
            {trend}%
          </span>
          {trendLabel && (
            <span className="text-xs text-muted-foreground">{trendLabel}</span>
          )}
        </div>
      )}
    </div>
  );
}