Stat
A KPI tile — a labelled figure with an optional signed delta and a slot for a trend sparkline.
import { ... } from '@corndev/ui' HTML
<div class="corn-stat" data-size="md">
<span class="corn-stat-label">Monthly revenue</span>
<span class="corn-stat-value">$4.2M</span>
<span class="corn-stat-delta" data-trend="good">
<span class="corn-stat-delta-arrow" aria-hidden="true">▲</span>+12.4%
<span class="corn-stat-delta-period">vs last month</span>
</span>
</div>
Classes
| Class |
|---|
.corn-stat |
.corn-stat-label |
.corn-stat-value |
.corn-stat-delta |
.corn-stat-delta-arrow |
.corn-stat-delta-period |
.corn-stat-trend |
Attributes
| On | Attribute | Values |
|---|---|---|
.corn-stat-delta | data-trend | good|bad|neutral |
.corn-stat | data-size | sm|md|lg |
.corn-stat | data-hero | present or absent |
Vanilla JS
Required for behaviour — adds formats the value, resolves the delta intent, and builds any label, value or delta element the markup does not already provide.
import { createStat } from '@corndev/ui';
import '@corndev/ui/theme';
const el = document.querySelector('#target');
const instance = createStat(el, { /* options */ });
Options
| Option | Type | Default | Description |
|---|---|---|---|
label | string | undefined | Short name for the metric. Sentence case, no trailing colon. |
value | number|string | undefined | The figure. Numbers are compacted unless format is false. |
delta | number | undefined | Signed change against a previous period. Omit for a tile with no comparison. |
deltaSuffix | string | '%' | Unit rendered after the delta. |
deltaPeriod | string | undefined | What the delta compares against, e.g. ‘vs last week’. |
goodDirection | 'up'|'down'|'neutral' | 'up' | Which direction counts as good. Set ‘down’ for metrics where falling is better (churn, latency, error rate). |
format | boolean | true | Auto-compact numeric values: 1,284 / 12.9K / 4.2M. |
locale | string | undefined | BCP-47 tag for number formatting. Defaults to the runtime locale. |
size | 'sm'|'md'|'lg' | 'md' | |
hero | boolean | false | Display-size value. Use at most one per view. |
React
Stat — from @corndev/ui-react.
The props are the same as the options above, plus className.
Default
<Stat label="Monthly revenue" value={4200000} delta={12.4} deltaPeriod="vs last month" />Direction is not the same as goodness
The delta’s colour is its direction multiplied by whether that direction is good. Churn rising is bad; latency falling is good. Set goodDirection="down" for metrics where a smaller number is the win — leave it at the default and the tile paints half of a real dashboard backwards.
The arrow always points the way the number actually moved. Only the colour changes.
<Stat label="Signups" value={1284} delta={8.2} deltaPeriod="vs last week" />
<Stat label="Churn rate" value="2.4%" delta={-0.6} deltaPeriod="vs last quarter" goodDirection="down" />
<Stat label="Error rate" value="0.8%" delta={0.3} deltaPeriod="vs yesterday" goodDirection="down" />Colour is never the only channel. The arrow glyph and the +/− sign carry the direction on their own, so the delta still reads in greyscale, in print, and under colour-vision deficiency.
Value formatting
Numbers are compacted once the digits crowd — below 10,000 they are grouped in full, because 1,284 reads better than 1.3K and keeps information people want at that magnitude.
| Input | Rendered |
|---|---|
1284 | 1,284 |
12900 | 12.9K |
4200000 | 4.2M |
Pass a string to render it verbatim, or format={false} to keep a number unformatted. Formatting follows the runtime locale unless you pass locale.
<Stat label="Grouped" value={1284} />
<Stat label="Compacted" value={12900} />
<Stat label="Verbatim string" value="$4.2M" />Sizes
<Stat label="Small" value={842} size="sm" />
<Stat label="Medium" value={842} size="md" />
<Stat label="Large" value={842} size="lg" />Hero
The single figure a view leads with, at display size. Use at most one per view — a page of hero numbers has no lead at all.
<Paper padding="lg">
<Stat label="Annual recurring revenue" value={51400000} delta={18.2} deltaPeriod="year over year" hero />
</Paper>Trend slot
Children render under the figure in .corn-stat-trend, sized for a sparkline. A trend is optional — a bare tile is a complete, correct stat.
Typography
The value uses the font’s proportional figures. tabular-nums gives every digit the width of a 0, which reads loose at display sizes; reserve it for columns that must align vertically, like table rows and axis ticks.