ข้ามไปเนื้อหา
WhereUI

ค้นหาในเอกสาร

ค้นหาชื่อ component หรือหน้าเอกสาร

Stat Card

WhereUI

การ์ดตัวเลข KPI พร้อมป้ายกำกับ ไอคอน และการเปลี่ยนแปลงขึ้น/ลง/คงที่ ตัวเลขใช้ tabular-nums ให้ต่อกันเป็นคอลัมน์สวยงาม

พนักงานทั้งหมด
248
+2.5% จากไตรมาสก่อน
รออนุมัติ
12
-8 รายการจากสัปดาห์ก่อน
อัตราลาคงเหลือ
96.2%

ติดตั้ง

Terminal
pnpm dlx shadcn@latest add @whereui/stat-card

ต้องผูก registry และติดตั้ง @whereui/theme นำหน้าเสมอเมื่อติดตั้งครั้งแรก

การใช้งาน

import { StatCard } from "@/components/ui/stat-card"<StatCard  label="พนักงานทั้งหมด"  value={248}  change={{ trend: "up", value: "+2.5% จากไตรมาสก่อน" }}/>

ตัวอย่างเพิ่มเติม

แนวโน้มลง คงที่ และไอคอน
ค่าใช้จ่ายเดินทางเดือนนี้
฿24,800
+12% จากเดือนก่อน
ชั่วโมงล่วงเวลาสะสม
328
เท่ากับเดือนก่อน
วันลาคงเหลือเฉลี่ย
7.5 วัน
-1.2 วันจากปีก่อน

Props

proptypeค่าเริ่มต้นคำอธิบาย
labelReact.ReactNode—ป้ายตัวชี้วัด เช่น "พนักงานทั้งหมด"
valueReact.ReactNode—ตัวเลขหรือข้อความหลัก ขนาดใหญ่ — ตัวเลขแนะนำ <Money> เมื่อเป็นเงิน
iconReact.ReactNode—ไอคอนมุมขวาบน เช่น <UsersIcon />
change{ trend: "up" | "down" | "flat"; value: string }—การเปลี่ยนแปลงเทียบก่อนหน้า — up สีเขียว down สีแดง flat สีเทา พร้อมไอคอนลูกศร

ข้อควรรู้

  • วางเรียงเป็นตารางด้วย grid เช่น grid gap-4 sm:grid-cols-3 — การ์ดยืดเต็มคอลัมน์เอง

ซอร์สโค้ด

components/ui/stat-card.tsx
import * as React from "react"import {  MinusIcon,  TrendingDownIcon,  TrendingUpIcon,} from "lucide-react"import { cn } from "cn"import { Card } from "@/components/ui/card"export type StatCardChange = {  /** ทิศทางการเปลี่ยนแปลง — up สีเขียว, down สีแดง, flat สีเทา */  trend: "up" | "down" | "flat"  /** ข้อความการเปลี่ยนแปลง เช่น "+2.5%" หรือ "อดทนานี้ 12 รายการ" */  value: string}const changeTrendClasses = {  up: "text-success",  down: "text-destructive",  flat: "text-muted-foreground",} as constconst changeTrendIcons = {  up: TrendingUpIcon,  down: TrendingDownIcon,  flat: MinusIcon,} as constfunction StatCard({  className,  label,  value,  icon,  change,  ...props}: React.ComponentProps<"div"> & {  /** ป้ายตัวชี้วัด เช่น "พนักงานทั้งหมด" */  label: React.ReactNode  /** ตัวเลข KPI */  value: React.ReactNode  /** ไอคอนมุมขวาบน */  icon?: React.ReactNode  /** การเปลี่ยนแปลงเทียบก่อนหน้า */  change?: StatCardChange}) {  const TrendIcon = change ? changeTrendIcons[change.trend] : null  return (    <Card data-slot="stat-card" className={cn("gap-0 px-4", className)} {...props}>      <div className="flex items-start justify-between gap-2">        <div className="text-sm text-muted-foreground">{label}</div>        {icon ? (          <div            data-slot="stat-card-icon"            aria-hidden="true"            className="mt-0.5 shrink-0 text-muted-foreground [&_svg]:size-4"          >            {icon}          </div>        ) : null}      </div>      <div        data-slot="stat-card-value"        className="mt-2 font-heading text-2xl leading-tight font-semibold tracking-tight tabular-nums"      >        {value}      </div>      {change && TrendIcon ? (        <div          data-slot="stat-card-change"          className={cn(            "mt-1.5 flex items-center gap-1 text-xs font-medium",            changeTrendClasses[change.trend]          )}        >          <TrendIcon aria-hidden="true" className="size-3.5" />          {change.value}        </div>      ) : null}    </Card>  )}export { StatCard }