OPERATOR

StatCard

Basic

LATENCY42 ms

Trend

When trend is omitted, direction follows the sign of delta. The color follows the direction too: up is the success color and down the error color. That is wrong for a metric where lower is better, such as errors, so say what the change means with trendIntent (see below).

THROUGHPUT1.2k rps+12%
ERRORS3-5%
QUEUE00%

What the change means

trendIntent says whether the change is good, bad or neither, and sets the trend color independently of the arrow: positive is the success color, negative the error color and neutral the dim one. Falling errors or latency are positive; a rising count of critical alarms is negative. Leave it out and the color follows the direction, as before. The arrow and the change text stay as the cue that does not rely on color.

CRITICAL ALARMS9+4
OPEN WORK ORDERS31+2

Caption

P95 LATENCY42 ms-12%over the last 5 minutes

Large values and narrow cards

A card keeps a minimum height of 169 px and a minimum width of 180 px. The width gives way inside a container narrower than that, so two cards can share a row on a phone, and nothing is truncated.

A number is never split between its digits. One with digit groups, such as 1,234,567.890, 12,34,567.89 or 1 234 567,89, wraps only after a group separator, and its last group stays with the unit. A currency sign or a suffix such as k or % stays with its number. If the last group and the unit are wider than the card, the value steps down in size to fit, but never below the body text size (--oprt-type-base). At that size, if they still do not fit together, the unit moves to its own line directly under the value. The digits are never split. Other text, such as a status, an identifier or a timestamp, breaks anywhere when it has to, and the unit stays beside its last character.

The card measures its own width, so it takes the width its grid cell or column gives it. In a row that sizes its items to their content, it is 180 px wide.

DISCHARGE PRESSURE1,234,567.890 kPa
LAST REPORT2026-10-02 14:03:09 UTC

Props

PROPTYPEDEFAULTREQUIRED
label

Short metric heading displayed uppercase and used as the default accessible name for the metric group. Values, units, and captions retain their casing. Override with aria-label or aria-labelledby when more context is needed.

string—yes
value

The metric value (string or number). Rendered in mono for digit alignment. A number is never split between its digits: one with digit groups (1,234,567.890) wraps only after a group separator, and its last group stays with the unit. When they do not fit the card the value steps down in size, never below the body text size (--oprt-type-base); at that size, if they still do not fit together, the unit moves to its own line under the value. Any other text breaks anywhere. Nothing is truncated or abbreviated.

string | number—yes
unit

Unit suffix shown beside the value, e.g. 'ms'. Its first word stays beside the last digits at every size above the body text size; only when they cannot fit together even at that size does the unit move to its own line under the value. The rest of a long unit wraps.

string—no
delta

Signed change. Trend is derived from its sign when 'trend' is omitted.

number—no
trend

Explicit trend direction. Overrides the sign of 'delta' when provided.

enum
up | down | flat
—no
trendIntent

Whether the change is good, bad or neither for the application, which sets the trend color independently of its direction: falling errors or latency are 'positive', rising critical alarms are 'negative'. Without it the color follows the direction (up is success, down is error). The arrow and the change text stay as the non-color cue.

enum
positive | negative | neutral
—no
deltaLabel

Human-readable change text, e.g. '+12%'.

string—no
caption

Secondary supporting line below the metric.

string—no

Accessibility

  • Named group using the visible label; override with aria-label or aria-labelledby.
  • Trend direction and magnitude form one labeled graphic, such as “trend down -12%”.
  • Arrow shapes convey direction alongside color. trendIntent changes the color only; the label stays the direction and the change. Values are display-only.
  • Long labels, values, change text and captions wrap instead of running out of the card.

Manifest entry

<StatCard label="LATENCY" value={42} unit="ms" delta={-12} deltaLabel="-12%" trendIntent="positive" />
View agent manifest
{
  "description": "Single-metric display: label, mono numeric value, and an optional trend indicator paired with an arrow glyph (non-color cue per WCAG 1.4.1). It keeps a minimum footprint (169 px tall, up to 180 px wide, narrower inside a narrower container) and its text wraps. It measures its own width, so a large number steps down in size to fit it (never below the body text size), and in a row that sizes its items to their content it is 180 px wide.",
  "props": {
    "label": {
      "type": "string",
      "required": true,
      "description": "Short metric heading displayed uppercase and used as the default accessible name for the metric group. Values, units, and captions retain their casing. Override with aria-label or aria-labelledby when more context is needed."
    },
    "value": {
      "type": "union",
      "types": [
        "string",
        "number"
      ],
      "required": true,
      "description": "The metric value (string or number). Rendered in mono for digit alignment. A number is never split between its digits: one with digit groups (1,234,567.890) wraps only after a group separator, and its last group stays with the unit. When they do not fit the card the value steps down in size, never below the body text size (--oprt-type-base); at that size, if they still do not fit together, the unit moves to its own line under the value. Any other text breaks anywhere. Nothing is truncated or abbreviated."
    },
    "unit": {
      "type": "string",
      "description": "Unit suffix shown beside the value, e.g. 'ms'. Its first word stays beside the last digits at every size above the body text size; only when they cannot fit together even at that size does the unit move to its own line under the value. The rest of a long unit wraps."
    },
    "delta": {
      "type": "number",
      "description": "Signed change. Trend is derived from its sign when 'trend' is omitted."
    },
    "trend": {
      "type": "enum",
      "values": [
        "up",
        "down",
        "flat"
      ],
      "description": "Explicit trend direction. Overrides the sign of 'delta' when provided."
    },
    "trendIntent": {
      "type": "enum",
      "values": [
        "positive",
        "negative",
        "neutral"
      ],
      "description": "Whether the change is good, bad or neither for the application, which sets the trend color independently of its direction: falling errors or latency are 'positive', rising critical alarms are 'negative'. Without it the color follows the direction (up is success, down is error). The arrow and the change text stay as the non-color cue."
    },
    "deltaLabel": {
      "type": "string",
      "description": "Human-readable change text, e.g. '+12%'."
    },
    "caption": {
      "type": "string",
      "description": "Secondary supporting line below the metric."
    }
  },
  "composable_with": [
    "Card",
    "DataTable",
    "Sidebar",
    "Toolbar"
  ],
  "never_inside": [
    "StatCard",
    "Badge",
    "Button"
  ],
  "example": "<StatCard label=\"LATENCY\" value={42} unit=\"ms\" delta={-12} deltaLabel=\"-12%\" trendIntent=\"positive\" />"
}

On this page