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.

CategoryBlocks
TypeBlock (ready-made section) (.mv-stats)
Statusstable
Also installsbadge, number-ticker
Keywordsstats, chiffres, numbers, kpi, metrics, counter, social proof, landing, editorial

When to use

Avoid when

Install

node scripts/add.mjs stats --out ./src/marvelous

AI 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 &amp; 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

NameTypeDefaultDescription
data-variantrow | cards | headlinerowrow (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

NameDescription
.mv-stats-header-eyebrow (mono kicker), -title (with -muted), optional -lead (placed on the right from 48rem).
dl.mv-stats-list > div.mv-stats-itemdt.mv-stats-label (mono label), dd.mv-stats-value (figure; <small> for the unit), dd.mv-stats-text (detail).
dd.mv-stats-trendTop-right slot: a badge, or text with data-trend="up|down" (also accepts the legacy .mv-stats-head class).
dd.mv-stats-chartChart slot holding an svg.mv-stats-spark drawn with currentColor (--mv-stats-chart-color).

CSS classes

NameDescription
mv-statsRoot section, mv-stats query container.
mv-stats-valueFigure (tabular numerals); put an <mv-number-ticker> in it.
mv-stats-iconOptional bordered icon square for the trend slot.

CSS variables

NameDefaultDescription
--mv-stats-columns4Columns from 48rem (2 below, 1 under 24rem).
--mv-stats-rows3headline: number of rows the first figure spans (items − 1).
--mv-stats-max72remMax width.
--mv-stats-bgtransparentSection background.
--mv-stats-rulevar(--mv-border-strong)Hairline color above each figure.
--mv-stats-chart-colorvar(--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.