Stat

Big-number display with a label, optional icon, trend delta (▲ ▼), tone-coloured value, and three sizes. Wraps CountUp automatically when given a numeric count, so the value animates in on mount. Pair with StatGroup to lay out a row with optional vertical dividers.

420
Sites shipped
99.9
Uptime
42
Avg load
last 30 days
v2.0
Version

Usage

import { Stat, StatGroup } from '@bwo-ui/react';

<Stat label="Sites shipped" count={420} />
<Stat label="Uptime" count={99.9} decimals={1} suffix="%" />
<Stat label="Version" value="v2.0" />

<Stat
  label="Monthly visitors"
  count={128400}
  delta={12.3}
  deltaSuffix="%"
  deltaLabel="vs last month"
/>

Delta indicator

Pass delta as a positive or negative number to render a trend line below the value — for up, for down, for zero. Colour follows the sign by default (positive → green, negative → red). For metrics where a lower number is better — bounce rate, error rate, page load time — pass goodWhen="down" to flip the colour mapping so a falling number reads as success.

128400
Monthly visitors
12%vs last month
3.4
Conversion rate
0.6 ppvs last month
38
Bounce rate
2 ppvs last month
0
Errors / day
0vs yesterday
{/* Higher is better (default) — positive delta is green */}
<Stat label="Monthly visitors" count={128400} delta={12.3} deltaSuffix="%" deltaLabel="vs last month" />

{/* Lower is better — negative delta is green */}
<Stat
  label="Bounce rate"
  count={38}
  suffix="%"
  delta={-2.1}
  deltaSuffix=" pp"
  deltaLabel="vs last month"
  goodWhen="down"
/>

Sizes

sm (24 px value) for table cells and dense dashboards, md (44 px, default) for general use, lg (56 px) for hero positions like the top of a report or a single-stat callout.

sm
128400
Monthly visitors
12%
md
128400
Monthly visitors
12%
lg
128400
Monthly visitors
12%
<Stat size="sm" label="Monthly visitors" count={128400} delta={12.3} deltaSuffix="%" />
<Stat           label="Monthly visitors" count={128400} delta={12.3} deltaSuffix="%" />
<Stat size="lg" label="Monthly visitors" count={128400} delta={12.3} deltaSuffix="%" />

With icons

Pass an inline SVG via icon to add a leading visual category cue. Keep icons at about 20 × 20 px and use currentColor so they pick up the surrounding muted colour automatically.

4910
Active users
48230
MRR
372
Orders
1.24
API calls
<Stat icon={<UsersIcon />}  label="Active users" count={4910} />
<Stat icon={<DollarIcon />} label="MRR"          count={48230} prefix="$" />
<Stat icon={<CartIcon />}   label="Orders"       count={372} />
<Stat icon={<BoltIcon />}   label="API calls"    count={1.24} decimals={2} suffix=" M" />

Tone

Colour the value itself when the stat's state itself is meaningful — green when a target's been hit, yellow as a warning, red as a problem. Tone applies only to the value; delta colours continue to follow goodWhen.

4910
tone=default
4910
tone=success
4910
tone=warning
12
tone=danger
<Stat tone="default" label="tone=default" count={4910} />
<Stat tone="success" label="tone=success" count={4910} />
<Stat tone="warning" label="tone=warning" count={4910} />
<Stat tone="danger"  label="tone=danger"  count={12} />

Alignment

align controls how the value, label, and delta line up within the Stat's own box. start (default) is the natural left-rail layout; center is for symmetric dashboard cards; end right-aligns everything for a table's last column or a number column in a report.

420
Start
5%
420
Center
5%
420
End
5%
<Stat align="start"  label="Start"  count={420} delta={5} deltaSuffix="%" />
<Stat align="center" label="Center" count={420} delta={5} deltaSuffix="%" />
<Stat align="end"    label="End"    count={420} delta={5} deltaSuffix="%" />

StatGroup

Wrap multiple Stats in a StatGroup to lay them out as a row. The divided prop adds a 1 px vertical line between each item — useful for report headers and the "at a glance" row at the top of a dashboard.

Plain group
12834
Visitors
420
Conversions
48230
Revenue
divided
12834
Visitors
8%
420
Conversions
1%
48230
Revenue
13%
{/* Plain row */}
<StatGroup>
  <Stat label="Visitors"    count={12834} />
  <Stat label="Conversions" count={420} />
  <Stat label="Revenue"     count={48230} prefix="$" />
</StatGroup>

{/* With vertical dividers between items */}
<StatGroup divided>
  <Stat label="Visitors"    count={12834} delta={8.2}  deltaSuffix="%" />
  <Stat label="Conversions" count={420}   delta={-1.4} deltaSuffix="%" />
  <Stat label="Revenue"     count={48230} prefix="$" delta={12.7} deltaSuffix="%" />
</StatGroup>

Dashboard recipe

The canonical dashboard layout: a 4-up grid of Card-wrapped stats. Use size="sm", icons for visual scanning, deltas with appropriate goodWhen, and tone="danger" on the error counter so problems stand out.

4910
Active users
6%
48230
MRR
13%
38
Bounce rate
2 pp
37
Errors
9
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12 }}>
  <Card pad="compact">
    <Stat size="sm" icon={<UsersIcon />}  label="Active users" count={4910}
          delta={6.2}  deltaSuffix="%" />
  </Card>
  <Card pad="compact">
    <Stat size="sm" icon={<DollarIcon />} label="MRR"          count={48230} prefix="$"
          delta={12.7} deltaSuffix="%" />
  </Card>
  <Card pad="compact">
    <Stat size="sm" icon={<CartIcon />}   label="Bounce rate"  count={38}    suffix="%"
          delta={-2.1} deltaSuffix=" pp" goodWhen="down" />
  </Card>
  <Card pad="compact">
    <Stat size="sm" icon={<BoltIcon />}  tone="danger" label="Errors" count={37}
          delta={9} goodWhen="down" />
  </Card>
</div>

Hero stat

Single, oversized stat for the top of a report. Combine size="lg"with a contextual badge or status pill on the side.

482310
Total revenue this quarter
18%vs last quarter
Live
<Card>
  <div style={{ display: 'flex', justifyContent: 'space-between' }}>
    <Stat
      size="lg"
      label="Total revenue this quarter"
      count={482310}
      prefix="$"
      delta={18.4}
      deltaSuffix="%"
      deltaLabel="vs last quarter"
    />
    <Badge variant="green" size="sm">Live</Badge>
  </div>
</Card>

Accessibility

Stat props

PropTypeDefaultDescription
labelReactNodeCaption — what the number measures.
countnumberNumeric value — animates from 0 via `CountUp`. Use `value` for non-numeric.
valueReactNodeStatic value for non-numeric stats (e.g. `"v2.0"`). Mutually exclusive with `count`.
decimalsnumber0Decimal places — used by `count` and the `delta` display.
prefixstringPrepended to the count (e.g. `"$"`).
suffixstringAppended to the count (e.g. `"%"`, `" ms"`).
hintReactNodeOptional small sub-line under the label.
iconReactNodeLeading inline SVG. Renders `aria-hidden`; ~20 × 20 px.
size'sm' | 'md' | 'lg''md'24 / 44 / 56 px value font.
align'start' | 'center' | 'end''start'Content alignment within the stat.
tone'default' | 'success' | 'warning' | 'danger''default'Colour the value itself for state-driven stats. Does not affect the delta colour.
deltanumberTrend amount. Renders `▲`/`▼`/`→` based on sign; colour follows `goodWhen`.
deltaPrefixstringPrepended to the delta value (e.g. `"$"`).
deltaSuffixstringAppended to the delta value (e.g. `"%"`, `" pp"`).
deltaLabelReactNodeContext text after the delta — e.g. `"vs last month"`.
goodWhen'up' | 'down''up'Whether higher or lower is good. Drives delta colour. Use `"down"` for bounce rate, error rate, load time, etc.
…restHTMLAttributes<HTMLDivElement>Native div attributes are forwarded.

StatGroup props

PropTypeDefaultDescription
dividedbooleanfalseRender a 1 px vertical line between each child stat.
size'sm' | 'md' | 'lg'Adjusts the gap between items. Children still set their own `size` individually.
…restHTMLAttributes<HTMLDivElement>Native div attributes are forwarded.