AniUI

Stat Card

KPI display card with value, trend indicator, and change percentage.

Installation#

npx @aniui/cli add stat-card
Web preview — components render natively on iOS & Android
import { StatCard } from "@/components/ui/stat-card";

export function MyScreen() {
  return (
    <View className="flex-row gap-4 p-4">
      <StatCard
        label="Revenue"
        value="$12,345"
        change={12.5}
        trend="up"
        className="flex-1"
      />
      <StatCard
        label="Users"
        value="1,234"
        change={-3.2}
        trend="down"
        className="flex-1"
      />
    </View>
  );
}

Usage#

app/index.tsx
import { StatCard } from "@/components/ui/stat-card";

export function MyScreen() {
  return (
    <View className="flex-row gap-4 p-4">
      <StatCard
        label="Revenue"
        value="$12,345"
        change={12.5}
        trend="up"
        className="flex-1"
      />
      <StatCard
        label="Users"
        value="1,234"
        change={-3.2}
        trend="down"
        className="flex-1"
      />
    </View>
  );
}

Props#

PropTypeDefault
label
string
-
value
string | number
-
change
number
-
trend
"up" | "down" | "neutral"
-
icon
React.ReactNode
-
className
string
-

Also accepts all View props.

Accessibility#

  • accessibilityRole="summary" for KPI display.
  • Value, trend, and change percentage are announced together for context.

Source#

components/ui/stat-card.tsx
import React from "react";
import { View, Text } from "react-native";
import { cn } from "@/lib/utils";

export interface StatCardProps extends React.ComponentPropsWithoutRef<typeof View> {
  className?: string;
  label: string;
  value: string | number;
  change?: number;
  trend?: "up" | "down" | "neutral";
  icon?: React.ReactNode;
}

export function StatCard({ className, label, value, change, trend, icon, ...props }: StatCardProps) {
  const trendColor =
    trend === "up" ? "text-green-500" : trend === "down" ? "text-destructive" : "text-muted-foreground";
  const trendArrow = trend === "up" ? "↑" : trend === "down" ? "↓" : "";

  return (
    <View
      className={cn("rounded-lg border border-border bg-card p-4", className)}
      accessibilityRole="summary"
      {...props}
    >
      <View className="flex-row items-center justify-between mb-2">
        <Text className="text-sm text-muted-foreground">{label}</Text>
        {icon && <View>{icon}</View>}
      </View>
      <Text className="text-2xl font-bold text-card-foreground">{value}</Text>
      {change !== undefined && (
        <View className="flex-row items-center mt-1 gap-1">
          <Text className={cn("text-sm font-medium", trendColor)}>
            {trendArrow} {change > 0 ? "+" : ""}{change}%
          </Text>
        </View>
      )}
    </View>
  );
}