Stats — .mv-stats
Key figures section with animated counters (number-ticker): ruled columns with mono labels, KPI cards with a trend slot and sparkline, or one oversized headline figure beside a stacked ledger.
| Category | Blocks |
|---|---|
| Type | Block (ready-made section) (.mv-stats) |
| Status | stable |
| Also installs | badge, number-ticker |
| Keywords | stats, chiffres, numbers, kpi, metrics, counter, social proof, landing, editorial |
When to use
- A landing page needs key figures with animated counters in editorial ruled columns
- KPI cards should show a trend badge and a sparkline under each figure
- One oversized headline figure should lead, with supporting numbers in a ledger beside it
Avoid when
- Figures are live app metrics that need axes, tooltips and time periods → use Chart instead
Install
node scripts/add.mjs stats --out ./src/marvelousAI agent with the Marvelous UI MCP server: install_components({ slugs: ["stats"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Files copied (dependencies included): tokens/tokens.css, core/base.css, components/stats/stats.css, components/badge/badge.css, core/dom.js, core/element.js, core/motion.js, core/observe.js, components/number-ticker/number-ticker.js, components/number-ticker/number-ticker.css.
Usage
Canonical markup — start from it and customize with attributes, data-* and CSS variables:
<mv-tabs id="stats-demo" value="row" data-size="sm" style="gap:0;background:var(--mv-bg)">
<style>#stats-demo > [role="tablist"] { justify-self: center; margin: .75rem auto 0; }</style>
<div role="tablist" aria-label="Block variant">
<button role="tab" data-value="row">Row</button>
<button role="tab" data-value="cards">Cards</button>
<button role="tab" data-value="headline">Headline</button>
</div>
<!-- ═════════ Row (default) ═════════ -->
<div role="tabpanel" data-value="row">
<section class="mv-stats" aria-labelledby="st-row-title">
<div class="mv-stats-inner">
<header class="mv-stats-header">
<p class="mv-stats-eyebrow">Ledgerline in numbers</p>
<h2 class="mv-stats-title" id="st-row-title">The figures our customers <span class="mv-stats-muted">take to their board.</span></h2>
<p class="mv-stats-lead">Median results across 3,200 finance teams, measured over their first two quarters on Ledgerline.</p>
</header>
<dl class="mv-stats-list">
<div class="mv-stats-item">
<dt class="mv-stats-label">Faster month-end close</dt>
<dd class="mv-stats-value"><mv-number-ticker value="62"></mv-number-ticker><small>%</small></dd>
<dd class="mv-stats-text">From 9.8 working days down to 3.7</dd>
</div>
<div class="mv-stats-item">
<dt class="mv-stats-label">Lines matched automatically</dt>
<dd class="mv-stats-value"><mv-number-ticker value="98.6" decimals="1" delay="120"></mv-number-ticker><small>%</small></dd>
<dd class="mv-stats-text">Without a single custom rule</dd>
</div>
<div class="mv-stats-item">
<dt class="mv-stats-label">Finance teams</dt>
<dd class="mv-stats-value"><mv-number-ticker value="3200" delay="240"></mv-number-ticker></dd>
<dd class="mv-stats-text">In 31 countries, from seed to listed</dd>
</div>
<div class="mv-stats-item">
<dt class="mv-stats-label">Reconciled in 2025</dt>
<dd class="mv-stats-value"><mv-number-ticker value="41" prefix="$" delay="360"></mv-number-ticker><small>bn</small></dd>
<dd class="mv-stats-text">Across 212 million transactions</dd>
</div>
</dl>
</div>
</section>
</div>
<!-- ═════════ Cards ═════════ -->
<div role="tabpanel" data-value="cards">
<section class="mv-stats" data-variant="cards" aria-labelledby="st-cards-title" style="--mv-stats-bg:var(--mv-bg-subtle)">
<div class="mv-stats-inner">
<header class="mv-stats-header">
<p class="mv-stats-eyebrow">September close · Harbor & Pine Group</p>
<h2 class="mv-stats-title" id="st-cards-title">Your close, <span class="mv-stats-muted">at a glance.</span></h2>
</header>
<dl class="mv-stats-list">
<div class="mv-stats-item">
<dt class="mv-stats-label">Days to close</dt>
<dd class="mv-stats-trend"><span class="mv-badge" data-variant="success" data-shape="pill">−1.4 d</span></dd>
<dd class="mv-stats-value"><mv-number-ticker value="3.2" decimals="1"></mv-number-ticker><small>days</small></dd>
<dd class="mv-stats-text">Best month since you joined</dd>
<dd class="mv-stats-chart" aria-hidden="true"><svg class="mv-stats-spark" viewBox="0 0 200 48" preserveAspectRatio="none"><path d="M0 8 29 12 57 10 86 20 114 22 143 30 171 34 200 40V48H0z" fill="currentColor" opacity=".08"/><path d="M0 8 29 12 57 10 86 20 114 22 143 30 171 34 200 40" fill="none" stroke="currentColor" stroke-width="1.5" vector-effect="non-scaling-stroke"/></svg></dd>
</div>
<div class="mv-stats-item">
<dt class="mv-stats-label">Auto-matched</dt>
<dd class="mv-stats-trend"><span class="mv-badge" data-variant="success" data-shape="pill">+0.8 pt</span></dd>
<dd class="mv-stats-value"><mv-number-ticker value="98.6" decimals="1" delay="100"></mv-number-ticker><small>%</small></dd>
<dd class="mv-stats-text">1,284 of 1,302 bank lines</dd>
<dd class="mv-stats-chart" aria-hidden="true"><svg class="mv-stats-spark" viewBox="0 0 200 48" preserveAspectRatio="none"><path d="M0 36 29 34 57 30 86 31 114 22 143 20 171 14 200 10V48H0z" fill="currentColor" opacity=".08"/><path d="M0 36 29 34 57 30 86 31 114 22 143 20 171 14 200 10" fill="none" stroke="currentColor" stroke-width="1.5" vector-effect="non-scaling-stroke"/></svg></dd>
</div>
<div class="mv-stats-item">
<dt class="mv-stats-label">Hours saved</dt>
<dd class="mv-stats-trend"><span class="mv-badge" data-variant="success" data-shape="pill">+12 h</span></dd>
<dd class="mv-stats-value"><mv-number-ticker value="126" delay="200"></mv-number-ticker><small>h</small></dd>
<dd class="mv-stats-text">Across a team of seven</dd>
<dd class="mv-stats-chart" aria-hidden="true"><svg class="mv-stats-spark" viewBox="0 0 200 48" preserveAspectRatio="none"><path d="M0 40 29 38 57 32 86 34 114 26 143 24 171 18 200 14V48H0z" fill="currentColor" opacity=".08"/><path d="M0 40 29 38 57 32 86 34 114 26 143 24 171 18 200 14" fill="none" stroke="currentColor" stroke-width="1.5" vector-effect="non-scaling-stroke"/></svg></dd>
</div>
<div class="mv-stats-item">
<dt class="mv-stats-label">Open exceptions</dt>
<dd class="mv-stats-trend"><span class="mv-badge" data-variant="warning" data-shape="pill">+3</span></dd>
<dd class="mv-stats-value"><mv-number-ticker value="18" delay="300"></mv-number-ticker></dd>
<dd class="mv-stats-text">11 are missing receipts</dd>
<dd class="mv-stats-chart" aria-hidden="true"><svg class="mv-stats-spark" viewBox="0 0 200 48" preserveAspectRatio="none"><path d="M0 30 29 26 57 34 86 28 114 32 143 24 171 28 200 20V48H0z" fill="currentColor" opacity=".08"/><path d="M0 30 29 26 57 34 86 28 114 32 143 24 171 28 200 20" fill="none" stroke="currentColor" stroke-width="1.5" vector-effect="non-scaling-stroke"/></svg></dd>
</div>
</dl>
</div>
</section>
</div>
<!-- ═════════ Headline ═════════ -->
<div role="tabpanel" data-value="headline">
<section class="mv-stats" data-variant="headline" aria-labelledby="st-head-title">
<div class="mv-stats-inner">
<header class="mv-stats-header">
<p class="mv-stats-eyebrow">2025 annual report</p>
<h2 class="mv-stats-title" id="st-head-title">A year of books, <span class="mv-stats-muted">closed on time.</span></h2>
</header>
<dl class="mv-stats-list">
<div class="mv-stats-item">
<dt class="mv-stats-label">Reconciled through Ledgerline</dt>
<dd class="mv-stats-value"><mv-number-ticker value="41" prefix="$"></mv-number-ticker><small>bn</small></dd>
<dd class="mv-stats-text">Every dollar matched to a document, approved by a person and locked in a signed audit log.</dd>
</div>
<div class="mv-stats-item">
<dt class="mv-stats-label">Closes completed</dt>
<dd class="mv-stats-value"><mv-number-ticker value="36400" delay="150"></mv-number-ticker></dd>
<dd class="mv-stats-text">91% of them on or before day five</dd>
</div>
<div class="mv-stats-item">
<dt class="mv-stats-label">Audits passed</dt>
<dd class="mv-stats-value"><mv-number-ticker value="1180" delay="300"></mv-number-ticker></dd>
<dd class="mv-stats-text">With read-only auditor access</dd>
</div>
<div class="mv-stats-item">
<dt class="mv-stats-label">Uptime</dt>
<dd class="mv-stats-value"><mv-number-ticker value="99.98" decimals="2" delay="450"></mv-number-ticker><small>%</small></dd>
<dd class="mv-stats-text">Measured by an independent monitor</dd>
</div>
</dl>
</div>
</section>
</div>
</mv-tabs>API
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
data-variant | row | cards | headline | row | row (default, or no attribute): figures on hairlines, 2 columns then --mv-stats-columns from 48rem; cards: bordered KPI cards, trend top right, dashed divider before the detail, full-bleed sparkline; headline: the first figure becomes oversized on the left, the others stack on the right as label | value rows (from 52rem). |
Content structure
| Name | Description |
|---|---|
.mv-stats-header | -eyebrow (mono kicker), -title (with -muted), optional -lead (placed on the right from 48rem). |
dl.mv-stats-list > div.mv-stats-item | dt.mv-stats-label (mono label), dd.mv-stats-value (figure; <small> for the unit), dd.mv-stats-text (detail). |
dd.mv-stats-trend | Top-right slot: a badge, or text with data-trend="up|down" (also accepts the legacy .mv-stats-head class). |
dd.mv-stats-chart | Chart slot holding an svg.mv-stats-spark drawn with currentColor (--mv-stats-chart-color). |
CSS classes
| Name | Description |
|---|---|
mv-stats | Root section, mv-stats query container. |
mv-stats-value | Figure (tabular numerals); put an <mv-number-ticker> in it. |
mv-stats-icon | Optional bordered icon square for the trend slot. |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-stats-columns | 4 | Columns from 48rem (2 below, 1 under 24rem). |
--mv-stats-rows | 3 | headline: number of rows the first figure spans (items − 1). |
--mv-stats-max | 72rem | Max width. |
--mv-stats-bg | transparent | Section background. |
--mv-stats-rule | var(--mv-border-strong) | Hairline color above each figure. |
--mv-stats-chart-color | var(--mv-fg) | Sparkline color. |
Accessibility
Definition list <dl>: each label (dt) is paired with its value and details (dd) in reading order. Counters expose their final value to screen readers; charts and icons are aria-hidden. Trends are written out in text, not conveyed by color alone.