Statistic

A key number with a label and an optional change.

Installation

Import the class, and @use the entry point in your global styles: without it the component renders unstyled.

import { Component } from '@angular/core';
import { WrStatistic, WrStatisticCountdown, WrStatisticGroup } from 'ngwr/statistic';

@Component({ imports: [WrStatistic, WrStatisticCountdown, WrStatisticGroup] })
export class MyComponent {}

Basic

<wr-statistic label="Active users" [value]="12345" />
<wr-statistic label="Revenue" [value]="9512" prefix="$" [delta]="12.4" />
Active users
12,345
Revenue
$9,512
+12.4%
Churn
1.8%
-0.4%

Dashboard grid

<wr-statistic-group> reflows to its own width (drag the corner): min sets the narrowest column, columns the most per row.

<wr-statistic-group [columns]="4" min="11rem">
  <wr-statistic label="Active users" [value]="12345" />
  <wr-statistic label="Revenue" [value]="9512" prefix="$" [delta]="12.4" />
  <wr-statistic label="Churn" [value]="1.8" [precision]="1" suffix="%" [delta]="-0.4" />
  <wr-statistic label="Sessions" [value]="48210" />
</wr-statistic-group>
Active users
12,345
Revenue
$9,512
+12.4%
Churn
1.8%
-0.4%
Sessions
48,210

Count up

A new number counts up from the old one; [animate]='false' turns it off.

<wr-statistic label="Revenue" prefix="$" [value]="revenue()" [precision]="2" [delta]="delta()" />
<wr-statistic label="Sessions" [value]="sessions()" />

protected readonly revenue = signal(9512.4);
protected readonly sessions = signal(48210);
protected readonly delta = signal(12.4);

constructor() {
  const id = setInterval(() => {
    this.revenue.set(Math.round(Math.random() * 5_000_00) / 100);
    this.sessions.set(Math.floor(Math.random() * 90_000));
    this.delta.set(Math.round((Math.random() * 40 - 20) * 10) / 10);
  }, 2000);
  inject(DestroyRef).onDestroy(() => clearInterval(id));
}
Revenue
$9,512.40
+12.4%
Sessions
48,210
Sessions (no animation)
48,210

Countdown

<wr-statistic-countdown> counts down to target; format takes D, H, m, s (doubled to pad) and SSS. A unit the format leaves out is carried into the largest one it shows, so HH:mm:ss reads 73:00:00 three days out.

<wr-statistic-countdown
  label="Launch in"
  [target]="launchDate"
  format="D days HH:mm:ss"
  (countdownEnd)="onLive()"
/>

protected readonly launchDate = new Date(Date.now() + 1000 * 60 * 60 * 36);
Launch in
1 days 11:59:59
Soon (fires in ~30s)
00:29

API

NameDescriptionTypeDefault
<wr-statistic>KPI card.component—
labelLabel above the value.string''
valueMain number or string shown.number | string | nullnull
prefixLeading glyph or symbol.string''
suffixTrailing glyph or unit.string''
precisionFixed decimals for numeric values.number0
animateCount up to a new numeric value (off for strings / reduced motion).booleantrue
durationCount-up duration in ms.number700
deltaChange vs previous period.number | nullnull
deltaSuffixUnit appended to the delta. Falls back to the statistic.deltaSuffix catalog key.string | nullnull
<wr-statistic-group>Grid that reflows to its own width.component—
minMinimum column width before the grid reflows to fewer columns.string'12rem'
columnsCap on columns for a wide container (0 = uncapped).number0
<wr-statistic-countdown>Live countdown variant.component—
targetrequiredDate or timestamp to count down to.Date | string | number—
labelLabel above the value.string''
formatFormat string for the remaining time.string'HH:mm:ss'
endTextText shown once it reaches zero.string | nullnull
tickMsTick interval in milliseconds.number1000
(countdownEnd)Emits once when the target time is reached.void—

CSS variables

Set these on the component's selector or a wrapper, not on :root: the defaults are declared on ngwr/statistic's own element.

VariableDefaultDeclared on
--wr-statistic-affix-font-sizevar(--wr-text-lg).wr-statistic
--wr-statistic-affix-font-weightvar(--wr-font-weight-medium).wr-statistic
--wr-statistic-delta-font-sizevar(--wr-text-xs).wr-statistic
--wr-statistic-delta-font-weightvar(--wr-font-weight-semibold).wr-statistic
--wr-statistic-delta-gapvar(--wr-space-xs).wr-statistic
--wr-statistic-font-familyvar(--wr-font-family-base).wr-statistic
--wr-statistic-gapvar(--wr-space-xs).wr-statistic
--wr-statistic-group-font-familyvar(--wr-font-family-base).wr-statistic-group
--wr-statistic-group-gapvar(--wr-space-xl).wr-statistic-group +1 variant override
--wr-statistic-label-font-sizevar(--wr-text-sm).wr-statistic
--wr-statistic-label-line-heightvar(--wr-leading-normal).wr-statistic
--wr-statistic-value-font-sizevar(--wr-text-3xl).wr-statistic
--wr-statistic-value-font-weightvar(--wr-font-weight-semibold).wr-statistic
--wr-statistic-value-gapvar(--wr-space-xs).wr-statistic
--wr-statistic-value-letter-spacingvar(--wr-tracking-tight).wr-statistic
--wr-statistic-value-line-heightvar(--wr-leading-tight).wr-statistic

Dependencies

Built onCounter

See also