Skip to content
Data Display

Stat Card

The KPI tile every dashboard opens with: a label, one number, and how that number moved.

Walkthrough

1. Basic

A label, one number and how it moved. delta is a fraction — 0.124 is +12.4% — and its sign picks the arrow and the colour.

Revenue $48,210
increased by 12.4% vs last week
<script lang="ts">	import { StatCard } from 'omaris';</script>​<StatCard	class="w-72 max-w-full"	label="Revenue"	value={48210}	format={{ style: 'currency', currency: 'USD', maximumFractionDigits: 0 }}	delta={0.124}	deltaLabel="vs last week"/>

2. Kpi row

The row a dashboard opens with: one column on a phone, two on a tablet, four on a desktop. A Sparkline from omaris/chart goes in the chart snippet, and invert is for a metric where down is the good news.

Revenue $48,210
increased by 12.4% vs last week
Orders 1,284
increased by 6.1% vs last week
Refunds 23
decreased by 18% vs last week
Avg. delivery 42 min
increased by 5% vs last week
<script lang="ts">	import { StatCard } from 'omaris';	import { Sparkline } from 'omaris/chart';​	type Kpi = {		label: string;		value: number | string;		format?: Intl.NumberFormatOptions;		delta: number;		invert?: boolean;		trend: number[];		color: string;	};​	const KPIS: Kpi[] = [		{			label: 'Revenue',			value: 48210,			format: { style: 'currency', currency: 'USD', maximumFractionDigits: 0 },			delta: 0.124,			trend: [32, 35, 31, 38, 42, 40, 45, 44, 49, 52],			color: 'var(--chart-1)'		},		{			label: 'Orders',			value: 1284,			delta: 0.061,			trend: [90, 96, 94, 101, 99, 108, 112, 110, 118, 121],			color: 'var(--chart-2)'		},		{			label: 'Refunds',			value: 23,			delta: -0.18,			invert: true,			trend: [34, 31, 33, 29, 30, 27, 26, 28, 24, 23],			color: 'var(--chart-3)'		},		{			label: 'Avg. delivery',			value: '42 min',			delta: 0.05,			invert: true,			trend: [38, 39, 37, 40, 41, 39, 42, 43, 41, 42],			color: 'var(--chart-4)'		}	];</script>​<div class="grid w-full grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">	{#each KPIS as kpi (kpi.label)}		<StatCard			variant="elevated"			label={kpi.label}			value={kpi.value}			format={kpi.format}			delta={kpi.delta}			invert={kpi.invert}			deltaLabel="vs last week"		>			{#snippet chart()}<Sparkline data={kpi.trend} height={36} color={kpi.color} />{/snippet}		</StatCard>	{/each}</div>

3. States

loading keeps the label and swaps the rest for skeletons of the same size, so nothing jumps when the figure lands. animate counts up to it, and does nothing at all under reduced motion.

Active users
Conversion
<script lang="ts">	import { Button, StatCard } from 'omaris';​	let loading = $state(true);</script>​<div class="flex w-full max-w-2xl flex-col gap-4">	<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">		<StatCard {loading} animate label="Active users" value={8214} delta={0.041} deltaLabel="today">			{#snippet icon()}				...			{/snippet}		</StatCard>		<StatCard			{loading}			animate			variant="filled"			tone="tertiary"			label="Conversion"			value={0.0342}			format={{ style: 'percent', maximumFractionDigits: 2 }}			delta={-0.012}			deltaLabel="vs yesterday"		/>	</div>	<Button variant="tonal" class="self-start" onclick={() => (loading = !loading)}>		{loading ? 'Load figures' : 'Back to loading'}	</Button></div>

4. Interactive

Give it href or onclick and the whole tile is one target — state layer, ripple, and a press that gives under the finger.

<script lang="ts">	import { StatCard } from 'omaris';</script>​<div class="grid w-full max-w-2xl grid-cols-1 gap-4 sm:grid-cols-2">	<StatCard href="#" label="Open tickets" value={37} delta={-0.2} invert deltaLabel="since Monday">		{#snippet footer()}View the queue →{/snippet}	</StatCard>	<StatCard		href="#"		variant="elevated"		label="Next payout"		value={12480}		format={{ style: 'currency', currency: 'USD' }}		deltaLabel="Friday, 3 April"	>		{#snippet footer()}Payout schedule →{/snippet}	</StatCard></div>

5. Overridden

class on the tile wins over its own radius, classes reaches every part, and the caller's role, aria-label and dir stay. locale="ar-IQ" formats the Arabic way with Western digits, as every number here does.

الإيرادات ‏1,250,000 د.ع.‏
increased by 20‎%‎ مقارنة بالشهر الماضي
<script lang="ts">	import { StatCard } from 'omaris';</script>​<StatCard	class="w-72 max-w-full rounded-shape-2xl"	classes={{ value: 'text-primary', delta: 'rounded-shape-xs', icon: 'rounded-full' }}	role="group"	aria-label="الإيرادات هذا الشهر"	dir="rtl"	label="الإيرادات"	value={1250000}	format={{ style: 'currency', currency: 'IQD', maximumFractionDigits: 0 }}	locale="ar-IQ"	delta={0.2}	deltaLabel="مقارنة بالشهر الماضي">	{#snippet icon()}		...	{/snippet}</StatCard>