// preview in
saved for every page

Stat

Shows one key number, what it measures and how it changed, like revenue this month. Use a row of them at the top of a dashboard.

Pattern HTML articleServer componentSource ↗
minimal · light · #3fa34d
Revenue$48,250+14.2%vs. September
trend

Installation

Set up Camaleo once (Installation), then import what you need. It renders on the server.

import { Stat, StatLabel, StatValue, StatHelpText, StatDelta } from "@camaleo/react";

Anatomy

An <article> with the label, the value and a help line. The delta usually sits inside the help line, before the comparison. Every part has a data-slot you can target from CSS.

Examples

Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above.

minimal · light · #3fa34d
Revenue$48,250+14.2%vs. September
Active customers2,420+8.1%vs. September

Going up

trend="up" adds an arrow and the success color. Always say what you compare with, like "vs. September", or the change means nothing.

Conversion rate3.64%−0.2 ptsvs. September

Going down

trend="down" turns the arrow down and the color to danger. Write the change in the unit of the value: points for a rate, not a percent of a percent.

Monthly churn2.1%−0.4 ptsvs. September

When down is good

For churn, latency or costs, a drop is good news. Add sentiment="positive" to keep the down arrow but use the success color.

Refund rate1.2%0.0 ptssame as last week

No change

neutral (the default) shows no arrow and a muted color. Use it when the change is zero or too small to matter.

Revenue$48,250+14.2%96% of the $50,000 goal

Against a goal

The help line can compare with a goal instead of a past period. People see how far they are from it without a second number to read.

Sign-ups318+27today, vs. yesterday

Your own icon

Pass icon to match the icons of your product, or icon={null} to show the number alone. Give the icon aria-hidden, like the default arrow.

Open tickets
42+6 since yesterday

Without a help line

In a compact stat with no help line, add the comparison with VisuallyHidden. Screen readers then hear "+6 since yesterday", not a bare number.

Revenue$48,250+14.2%vs. the previous 30 days

Changing the period

Pick another period. The toggle group keeps the choice pressed and the stat updates in place, so the label and the layout don't jump.

In context

Stats usually come in a row of three or four inside a card, with one heading for the group. These are whole pieces of UI you can copy, in the skin you picked.

Store performance, October 2026

Revenue$48,250+14.2%vs. September
Orders1,842+12.3%vs. September
Conversion rate3.64%−0.2 ptsvs. September
Store dashboardCard · Stat

Subscriptions, Q3 2026

On track
Monthly recurring revenue$128,400+16.4%vs. Q2
Annual run rate$1.54M+18.2%vs. Q3 2025
Net revenue retention118%0 ptsgoal: above 115%
Subscription metricsCard · Stat · Badge

Cluster health

us-east-1
CPU42%of 32 cores
Memory6.2 GBof 16 GB
P99 latency18 msin the last hour
Server healthCard · Stat · Badge

Guidelines

Revenue$48,250+14.2%vs. September
DoWrite the sign in the text.

The arrow is hidden from screen readers and not everyone sees the color. "+14.2%" says the direction to everyone.

Revenue$48,25014.2%vs. September
Don’tDirection shown only by color.

Without the sign or the arrow, "14.2%" in green reads as a plain number to many people.

Revenue$48,250+14.2%vs. September
DoFormat the value and give its unit.

Currency, thousands separators and a percent sign tell people what the number is before they read the label.

Revenue4825014.2
Don’tRaw numbers.

"48250" and "14.2" leave people guessing: dollars or orders, percent or points.

Props

PropTypeDefaultDescription
trendStatTrend"neutral"Which way the number moved. Sets the arrow (neutral has none) and, unless sentiment is set, the color.
sentimentStatSentiment"positive" for `trend="up"`, "negative" for `trend="down"`, otherwise "neutral"Whether the change is good news: positive is green, negative is red. Set it when going down is good, like churn or latency: trend="down" sentiment="positive". The color is visual only; the text must say it.
iconReactNode—Replaces the arrow. Pass null to show the number alone. The arrow is hidden from screen readers, so the text must carry the sign.

Stat takes the attributes of <article>; StatLabel, StatValue and StatHelpText take those of <span>.

Styling hooks

Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the stat itself.

Attributes

data-trendup · down · neutral (on stat-delta)
data-sentimentpositive · negative · neutral (on stat-delta, sets the color)

Tokens it reads

Color

--cml-border-control--cml-card-border--cml-card-shadow--cml-danger--cml-fg--cml-fg-secondary--cml-success--cml-surface-raised

Shape & size

--cml-border-width--cml-radius-popover

Type & motion

--cml-font-control--cml-font-display--cml-font-label--cml-font-weight-display

This component only

--cml-corner-shape--cml-stat-bg--cml-stat-border--cml-stat-label-size--cml-stat-label-tracking--cml-stat-label-transform--cml-stat-label-weight--cml-stat-padding--cml-stat-radius--cml-stat-value-font--cml-stat-value-size--cml-stat-value-weight

Accessibility

TabA stat has no Tab stop. Tab only reaches buttons or links you put inside it.
Was this page helpful? · Edit this page on GitHub