Stat

Pro

A KPI/metric card for dashboards: a label, a big tabular-nums value, a directional trend chip, and optional icon or sparkline. Compose the named parts into a tile, then drop a row of them above a Data Table.

Total orders
1,429
12.4%
vs last month
Revenue
$84,200
8.1%
vs last month
Avg. order value
$58.92
2.3%
vs last month
Refunds
32
5.0%
vs last month

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Activate your Pro license (once per machine)npx koalaui-cli@latest login <key># Add this component (its dependencies come along)npx koalaui-cli@latest add stat

Usage#

Stat is composed from named parts, like Card. The Stat root owns the surface, variant, and density; the parts (StatLabel, StatValue, StatTrend) read it from context.

This example is part of Koala UI Pro

The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.

Have a license? Unlock it here

Anatomy#

A tile reads top-to-bottom: a StatHeader pairs the label with a tinted StatIcon (or an action), the StatValue carries the figure in tabular-nums so it never reflows, and a StatFooter sets the trend beside a muted comparison caption.

Total orders
1,429
12.4%
vs last month
import {  StatGroup,  Stat,  StatHeader,  StatLabel,  StatIcon,  StatValue,  StatFooter,  StatTrend,  StatCaption,  StatSparkline,} from "@/components/ui/stat"<StatGroup>  <Stat>    <StatHeader>      <StatLabel />      <StatIcon />    </StatHeader>    <StatValue />    <StatFooter>      <StatTrend />      <StatCaption />    </StatFooter>    <StatSparkline data={[...]} />  </Stat></StatGroup>

Group#

StatGroup fuses a row of tiles into one segmented surface, the way a dashboard bands its headline KPIs together instead of floating them as separate cards. The group owns the single border, radius, and shadow; each nested Stat senses the group and sheds its own chrome to lie flush, with hairline dividers between. Set the widest-breakpoint column count with columns (2 | 3 | 4 | 5 | 6); it steps down gracefully on narrow screens.

Total orders
1,429
12.4%
Revenue
$84,200
8.1%
Avg. order value
$58.92
2.3%
Refunds
32
5.0%

Inside a pane that already draws its own borders (a header band, a split view), variant="plain" drops the frame: no ring, radius, or shadow, only the dividers between tiles. The pane’s rules frame the band, so no edge is drawn twice and no rounded corner meets a straight line.

Open tickets
42
Median reply
3h 12m
Satisfaction
96%

The rest of the pane.

Trend#

StatTrend is a soft chip whose arrow and color come from direction: up reads green, down red, and neutral muted. For metrics where down is the good outcome (refunds, churn, bounce rate), set inverted: the color flips to match the meaning while the arrow keeps pointing the honest way. The chip never wraps or shrinks, so a “+1.1 pts” in a narrow tile stays one chip and the row beside it gives way.

Orders
1,429
12.4%
Avg. order value
$58.92
2.3%
Refunds
32
5.0%
Open tickets
17
0.0%

Sparkline#

StatSparkline is built on Chart in sparkline mode: a soft area fill under a trend line that bleeds to the bottom and side edges of the tile. It paints in currentColor, so set the hue with a text utility (text-success, text-destructive) and it themes across all four palettes for free. Pass tooltip to light up each point on hover with a gliding bubble.

Orders this week
18.2%
1,429
Refunds this week
9.0%
32

Count up#

Pass countUp to StatValue and the figure counts up from zero to its value the first time it scrolls into view, the same trigger the marketing sections use, re-counting each time it scrolls back in. It climbs fast and decelerates onto the final figure, so it reads as a real count-up. It reads the string children ("4,100+", "$4.2M", "4.6×") and preserves the prefix, suffix, and comma/decimal format as it counts, riding the built-in tabular-nums so the row never jitters as the count climbs. It no-ops for number-less content and honors prefers-reduced-motion by showing the final figure immediately.

4,100+
Teams building on Koala
$4.2M
Engineering time saved
4.6×
Faster to ship

Variants#

default sits on a hairline border with a soft shadow; outline drops the shadow for flat, gridded dashboards; elevated trades the border for a lifted shadow when a tile needs to float; plain has no tile at all.

Default
1,429
12.4%
Outline
1,429
12.4%
Elevated
1,429
12.4%
Plain
1,429
12.4%

Without a frame#

Most dashboards lead a chart or a card with one big figure, and that figure is not a tile. variant="plain" drops the ring, the shadow, the fill and the padding, and keeps everything else: the display-face figure, the density’s type ramp, and a tighter rhythm between the parts, since there is no frame left to space them against. Lay it on the sheet beside a chart, or inside a Card, where the card is the frame. Inside a StatGroup the group already owns the frame, so a plain tile keeps the group’s padding.

Net sales
$48,290
+8.1%
Sep 21–27, against the week before
Refunds
Money returned to customers this week.
$2,840
-4.2%
32 orders, 2.1% of sales

Parts on their own#

The parts do not need a Stat around them. StatValue, StatTrend, StatLabel and StatCaption (and the header, footer and icon rows) render anywhere with the plain look at the ambient density, so the headline figure of a chart card is a StatValue, and the trend chip beside a number in a description is a StatTrend, the same chip a tile carries. countUp works there too. Only StatSparkline needs a Stat, because it bleeds to the tile’s edges.

Orders
Placed on the storefront.
1,429
Sep 21–27
Traffic sources
12,480 visits+6.3%against last week

Density#

Density is Koala’s cross-cutting spacing axis (see Density). For Stat it tunes padding, gap, the icon tile, and the value size. compact is the dashboard default; comfortable is roomier. Set it per-tile or for a whole grid with DensityProvider.

Compact
1,429
12.4%
Comfortable
1,429
12.4%

Interactive#

A KPI tile is data, not a control, so it stays inert by default. When the whole tile should drill into a detail view, pass asChild to render it as a link and interactive to add the pointer, hover lift, and focus ring. For a per-tile menu instead, drop a Button into the header.

Total orders
1,429
12.4%
View all orders
Revenue
$84,200
8.1%
vs last month

API reference#

Stat

The tile root: owns the surface, variant and density, and shares them with its parts through context. Forwards all native <div> props; every part accepts className, merged last.

PropTypeDefaultDescription
variant"default" | "outline" | "elevated" | "plain""default"default is an edge ring plus a soft lift, outline the bare ring, elevated a card fill with a shadow, plain no frame or padding at all.
density"compact" | "comfortable""compact"Padding, gap, value size and icon tile. Inherits the nearest DensityProvider when omitted.
interactiveboolean-Adds the pointer, a hover lift and a focus ring, for a tile that is a link or button.
asChildbooleanfalseRenders onto the child element via Radix Slot (e.g. an <a>).

StatGroup

Fuses a row of tiles into one segmented surface with hairline dividers; nested Stats shed their own chrome. Forwards all native <div> props.

PropTypeDefaultDescription
variant"default" | "outline" | "elevated" | "plain""default"The group's frame, mirroring Stat's variants. elevated sets the card as the tiles' ground; plain drops the frame and keeps only the dividers, for a band inside a pane that already has its own borders.
columns2 | 3 | 4 | 5 | 64Columns at the widest breakpoint; steps down to one, then two, on narrower screens.
asChildbooleanfalseRenders onto the child element via Radix Slot.
CSS variableDescription
--surfaceSet to var(--card) by elevated; grouped tiles paint it as their opaque fill.

StatHeader

A row that sets the label on the left and an icon or action on the right. Forwards all native <div> props.

StatLabel

The metric's name, muted and medium weight. Renders inside a Stat or on its own. Forwards all native <div> props.

StatIcon

A tinted tile for a glyph, hidden from assistive tech. Forwards all native <div> props.

StatValue

The headline figure in the display face with tabular-nums, sized by density. Renders inside a Stat or on its own at the ambient density. Forwards all native <div> props.

PropTypeDefaultDescription
countUpbooleanfalseCounts a string figure ("$4.2M", "74%") up from zero each time it scrolls into view, keeping its prefix, suffix and format. Shows the final figure under reduced motion.

StatFooter

A row that pairs the trend with the caption. Forwards all native <div> props.

StatTrend

The trend chip: an arrow and a soft tone. Never wraps or shrinks. Forwards all native <span> props.

PropTypeDefaultDescription
direction"up" | "down" | "neutral""up"The arrow, and by default the tone: up green, down red, neutral muted.
invertedbooleanfalseFlips the tone without flipping the arrow, for metrics where down is good (churn, refunds).
Data attributeDescription
data-directionup, down or neutral.

StatCaption

The muted line that frames the figure (a period, a comparison). Forwards all native <div> props.

StatSparkline

A chromeless trend built on Chart, bleeding to the tile's bottom and side edges. Paints in currentColor, so set the hue with a text utility. Must sit inside a Stat; forwards native <div> props except children.

PropTypeDefaultDescription
data*number[]-The series, drawn as a soft area under a line.
strokeWidthnumber2Line stroke width in px.
tooltipbooleanfalseShows a gliding tooltip with each point's value on hover.
valueFormatter(value: number) => string-Formats each point's value in the tooltip.

FAQ#

The `Stat` root owns the surface, variant, and density; nest a `StatHeader` (with `StatLabel` plus an optional `StatIcon`), then `StatValue`, then a `StatFooter` pairing `StatTrend` with `StatCaption`. The parts read the root from context, so you never wire props between them.