---
title: 'Stat'
description: 'Composable metric components for highlighted values, trends, and labels.'
version: 10.104.0
generatedAt: 2026-04-17T18:46:11.945Z
checksum: 08ee69ee2cf524d4d12e50da5b28dab1961268780073012f1217e2ffecd712fb
---

# Stat

## Import

```tsx
import { Stat } from '@dnb/eufemia'
```

## Description

`Stat` contains components for prominent values with a label, where typography and visual emphasis are part of the component.

## Available components

- `Stat.Root` renders a definition list (`dl`).

  - `Stat.Label` renders descriptive text with dedicated typography and color for metric context (`dt`).

  - `Stat.Content` renders the main value as a definition description (`dd`).

- `Stat.Number` is the base value formatter built on the [NumberFormat](/uilib/components/number-format/) formatting logic.

- `Stat.Currency` and `Stat.Percent` are convenience wrappers around `Stat.Number`.

  - It adds typography-specific properties such as `fontSize`, `fontWeight` and `colorizeBySign`, along with `mainSize` and `auxiliarySize` as well as `mainWeight` and `auxiliaryWeight` that can be used to customize the visual emphasis of the different parts of the value (currency symbol or percent sign).

- `Stat.Trend` renders explicit `+` / `-` indicators with red/green background states and screen-reader text.

- `Stat.Rating` renders a star rating (defaults to 5 stars) and colorizes stars based on `value`. The `max` prop is clamped to `20` to prevent excessive DOM output; a console warning is emitted when the limit is exceeded.

- `Stat.Info` renders supporting text with a smaller, muted style.

- `Stat.Inline` is a horizontal layout container for grouping content elements like `Stat.Trend` and `Stat.Info` side by side with consistent spacing and alignment.

- `Stat.Text` renders custom content and supports properties such as `fontSize`, `fontWeight`, and `colorizeBySign`.

### Deprecated

- `Stat.Amount` is deprecated and will be removed in a future version. Use `Stat.Number` instead.

## Accessibility

- `Stat.Root` provides semantic definition-list markup (`dl`), where `Stat.Label` is rendered as `dt` and `Stat.Content` as `dd`.

- If the label also acts as a section heading, use a heading element inside `Stat.Label` (for example `H3`) to preserve a meaningful heading outline.

- Use `srLabel` to prepend context in the screen-reader text only, for example turning `1,234 kr` into `Revenue 1,234 kr` for screen readers.

- When e.g. `signDisplay="always"` is used, the sign is rendered as a separate visual element with CSS spacing, while the accessible text stays based on the formatted number string.

- All Stat variants keep dedicated accessibility handling. `Currency`, `Percent`, and `Trend` use a dedicated screen-reader value (`.dnb-sr-only`) based on the formatted content. `Rating` uses an accessible label (`role="img"` + `aria-label`) that includes value and max.

## Relevant links

- [Source code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-eufemia/src/components/stat)
- [Docs code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-design-system-portal/src/docs/uilib/components/stat)

## Demos

### Basic usage

```tsx
render(
  <Stat.Root>
    <Stat.Label>Revenue growth</Stat.Label>
    <Stat.Content direction="vertical">
      <Stat.Currency value={1234} signDisplay="always" />
      <Stat.Trend srLabel="Change">+12.4%</Stat.Trend>
      <Stat.Info>Some additional information.</Stat.Info>
    </Stat.Content>
  </Stat.Root>
)
```

### Root and Label

If the label acts as a section heading, place a heading element inside `Stat.Label` (for example `H3`).

```tsx
render(
  <Stat.Root>
    <Stat.Label>
      <H3>Revenue growth</H3>
    </Stat.Label>
    <Stat.Content direction="vertical">
      <Stat.Currency
        value={1234}
        mainSize="x-large"
        auxiliarySize="x-small"
      />
      <Stat.Trend srLabel="Growth trend">+12.4%</Stat.Trend>
    </Stat.Content>

    <Stat.Label top>Monthly change</Stat.Label>
    <Stat.Content direction="vertical">
      <Stat.Currency
        value={-1234}
        signDisplay="always"
        mainSize="x-large"
        auxiliarySize="x-small"
      />
      <Stat.Inline>
        <Stat.Trend srLabel="Change trend">-2.1%</Stat.Trend>
        <Stat.Info>(some additional information)</Stat.Info>
      </Stat.Inline>
    </Stat.Content>
  </Stat.Root>
)
```

#### Hidden Label

Use a visually hidden label (`srOnly`) when the visible UI context already describes the statistic.

```tsx
render(
  <Stat.Root>
    <Stat.Label srOnly>I'm a hidden label</Stat.Label>
    <Stat.Content>
      <Stat.Currency value={1234} />
    </Stat.Content>
  </Stat.Root>
)
```

### Currency

You can use `mainSize` and `auxiliarySize` to adjust the relative size of the currency symbol and the amount.

```tsx
render(
  <Stat.Root>
    <Stat.Label>Always show sign</Stat.Label>
    <Stat.Content>
      <Stat.Currency
        value={1234}
        mainSize="x-large"
        signDisplay="always"
        auxiliarySize="x-small"
      />
    </Stat.Content>

    <Stat.Label top>With suffix</Stat.Label>
    <Stat.Content>
      <Stat.Currency
        value={1234}
        currency="USD"
        suffix="/mnd"
        mainSize="x-large"
        auxiliarySize="x-small"
      />
    </Stat.Content>

    <Stat.Label top>
      Colorized using <Code>en-GB</Code> locale
    </Stat.Label>
    <Stat.Content>
      <Stat.Currency
        value={-1234.5}
        decimals={2}
        currency="USD"
        signDisplay="always"
        fontSize="medium"
        colorizeBySign
        locale="en-GB"
      />
    </Stat.Content>
  </Stat.Root>
)
```

### Currency within a Trend

```tsx
render(
  <Stat.Root>
    <Stat.Label>
      <DateFormat value="P1Y" />
    </Stat.Label>
    <Stat.Content direction="vertical">
      <Stat.Currency value={350234} srLabel="Annual revenue" />
      <Stat.Inline>
        <Stat.Trend>
          <Stat.Currency
            value={46692}
            signDisplay="always"
            srLabel="Revenue delta"
          />
        </Stat.Trend>
        <Stat.Info>
          (
          <Stat.Percent
            value={16.79}
            decimals={2}
            srLabel="Relative change"
          />)
        </Stat.Info>
      </Stat.Inline>
    </Stat.Content>
  </Stat.Root>
)
```

### Number

```tsx
render(
  <Stat.Root>
    <Stat.Label>Number</Stat.Label>
    <Stat.Content>
      <Stat.Number
        value={1234}
        signDisplay="always"
        mainSize="x-large"
        auxiliarySize="x-small"
      />
    </Stat.Content>

    <Stat.Label top>Number in Trend and Info</Stat.Label>
    <Stat.Content>
      <Stat.Trend tone="negative" srLabel="Negative trend">
        <Stat.Number value={-1234} signDisplay="always" />
      </Stat.Trend>
      <Stat.Info>
        (
        <Stat.Number value={1234} srLabel="Signed amount with currency" />)
      </Stat.Info>
    </Stat.Content>
  </Stat.Root>
)
```

### Percent

```tsx
render(
  <Stat.Root>
    <Stat.Label>Percentage</Stat.Label>
    <Stat.Content>
      <Stat.Percent
        value={12.3}
        mainSize="x-large"
        auxiliarySize="x-small"
      />
    </Stat.Content>

    <Stat.Label top>Percentage colorized</Stat.Label>
    <Stat.Content>
      <Stat.Percent
        value={0.1234}
        decimals={2}
        signDisplay="always"
        fontSize="medium"
        colorizeBySign
      />
    </Stat.Content>
  </Stat.Root>
)
```

### Percent colorized by sign

```tsx
render(
  <Stat.Root>
    <Stat.Label>Positive without signDisplay</Stat.Label>
    <Stat.Content>
      <Stat.Percent value={12.3} fontSize="medium" colorizeBySign />
    </Stat.Content>

    <Stat.Label top>Negative without signDisplay</Stat.Label>
    <Stat.Content>
      <Stat.Percent value={-12.3} fontSize="medium" colorizeBySign />
    </Stat.Content>

    <Stat.Label top>Zero without signDisplay</Stat.Label>
    <Stat.Content>
      <Stat.Percent value={0} fontSize="medium" colorizeBySign />
    </Stat.Content>
  </Stat.Root>
)
```

### Rating

```tsx
render(
  <Stat.Root>
    <Stat.Label>Stars rating</Stat.Label>
    <Stat.Content>
      <Stat.Rating value={4} />
    </Stat.Content>

    <Stat.Label top>Progressive rating</Stat.Label>
    <Stat.Content direction="vertical">
      <Stat.Rating variant="progressive" value={5} />
    </Stat.Content>
  </Stat.Root>
)
```

### Text

```tsx
render(
  <Stat.Root>
    <Stat.Label>Label</Stat.Label>
    <Stat.Content>
      <Stat.Text colorizeBySign={-123}>Custom content</Stat.Text>
    </Stat.Content>

    <Stat.Label top>With medium font weight and size</Stat.Label>
    <Stat.Content>
      <Stat.Text
        srLabel="Screen reader label"
        colorizeBySign={123}
        fontWeight="medium"
        fontSize="medium"
      >
        Larger and bolder
      </Stat.Text>
    </Stat.Content>
  </Stat.Root>
)
```

### With Subtle Label

Also, the order of the content and label can be switched for visual users (not screen readers), and the label is styled with the `subtle` variant to further de-emphasize it.

```tsx
function Example() {
  const { rating } = useTranslation().Stat
  return (
    <Grid.Container
      rowGap
      columnGap
      style={{
        gridAutoRows: '1fr',
      }}
    >
      <Grid.Item
        span={{
          small: [1, 12],
          medium: [1, 12],
          large: [1, 3],
        }}
      >
        <Card
          style={{
            height: '100%',
          }}
        >
          <Stat.Root visualOrder="content-label">
            <Stat.Label variant="subtle">
              <DateFormat value="P1Y" />
            </Stat.Label>
            <Stat.Content direction="vertical">
              <IconPrimary icon="arrow_up" top="x-small" />
              <Stat.Percent
                top="small"
                value={5.21}
                decimals={2}
                fontSize="basis"
                srLabel="Revenue growth percentage"
              />
            </Stat.Content>
          </Stat.Root>
        </Card>
      </Grid.Item>

      <Grid.Item
        span={{
          small: [1, 12],
          medium: [1, 12],
          large: [4, 6],
        }}
      >
        <Card
          style={{
            height: '100%',
          }}
        >
          <Stat.Root visualOrder="content-label">
            <Stat.Label variant="subtle">Yearly cost</Stat.Label>
            <Stat.Content direction="vertical">
              <Icon icon={globe_medium} />
              <Stat.Percent
                top="small"
                value={0.6}
                decimals={1}
                fontSize="basis"
              />
            </Stat.Content>
          </Stat.Root>
        </Card>
      </Grid.Item>

      <Grid.Item
        span={{
          small: [1, 12],
          medium: [1, 12],
          large: [7, 9],
        }}
      >
        <Card
          style={{
            height: '100%',
          }}
        >
          <Stat.Root visualOrder="content-label">
            <Stat.Label variant="subtle">Risiko</Stat.Label>
            <Stat.Content direction="vertical">
              <Stat.Rating variant="progressive" value={2} />
              <Stat.Info top variant="prominent">
                Lav
              </Stat.Info>
            </Stat.Content>
          </Stat.Root>
        </Card>
      </Grid.Item>

      <Grid.Item
        span={{
          small: [1, 12],
          medium: [1, 12],
          large: [10, 12],
        }}
      >
        <Card
          style={{
            height: '100%',
          }}
        >
          <Stat.Root visualOrder="content-label">
            <Stat.Label variant="subtle">Stars rating</Stat.Label>
            <Stat.Content direction="vertical">
              <Stat.Rating value={2} />
              <Stat.Info top variant="prominent">
                {rating.replace('%value', '2').replace('%max', '5')}
              </Stat.Info>
            </Stat.Content>
          </Stat.Root>
        </Card>
      </Grid.Item>
    </Grid.Container>
  )
}
render(<Example />)
```

### With AriaLive

Use the [AriaLive](/uilib/components/aria-live/) component to announce dynamic value updates to screen readers. Wrap `Stat.Root` with `AriaLive` so that changes are announced when the content updates.

```tsx
function Example() {
  const [value, setValue] = React.useState(1234)
  return (
    <Flex.Stack>
      <AriaLive variant="content">
        <Stat.Root>
          <Stat.Label>Revenue</Stat.Label>
          <Stat.Content>
            <Stat.Currency value={value} />
          </Stat.Content>
        </Stat.Root>
      </AriaLive>

      <Button
        text="Update value"
        variant="secondary"
        on_click={() => setValue((prev) => prev + 100)}
      />
    </Flex.Stack>
  )
}
render(<Example />)
```

## Stat.Currency

<PropertiesTable props={CurrencyProperties} />

## Stat.Percent

<PropertiesTable props={PercentProperties} />

## Stat.Number

```json
{
  "props": {
    "value": {
      "doc": "A number.",
      "type": "number",
      "status": "required"
    },
    "currency": {
      "doc": "Currency code (ISO 4217) or `true` to use the default `NOK`. Uses two decimals by default.",
      "type": ["string", "boolean"],
      "status": "optional"
    },
    "currencyDisplay": {
      "doc": "Use either empty/false to hide the sign/name or use `code` (NOK), `name` (kroner), `symbol` (kr) or `narrowSymbol` (for a shorter symbol variant). Defaults to `narrowSymbol` when the locale is `no` else we default to `code`.",
      "type": "string",
      "status": "optional"
    },
    "currencyPosition": {
      "doc": "Use either `before` or `after` to change/define the position of the currency. Defaults to `auto` (Browser API defaults, but with an exception, if the locale is `nb-NO` or `no`, use after as the default position).",
      "type": "string",
      "status": "optional"
    },
    "decimals": {
      "doc": "Set a number to define the number of decimals. Like `decimals=\"0\"` will ensure that decimals are simply not shown. The default decimals for currency usage are `2` (Browser API default).",
      "type": "number",
      "status": "optional"
    },
    "rounding": {
      "doc": "If `omit` is given, the decimal will NOT be rounded. If set to `half-even`, the value will be rounded to the nearest even number. If set to `half-up`, the fractional part is 0.5 or greater, the number is rounded up. If the fractional part is less than 0.5, the number is rounded down. Defaults to `half-up`.",
      "type": ["omit", "half-even", "half-up"],
      "status": "optional"
    },
    "signDisplay": {
      "doc": "When to display the sign for the number. Use `auto` (default) for negative numbers only, `always` to always display sign, `exceptZero` for positive and negative numbers but not zero, `negative` for negative numbers only including negative zero, or `never` to never display sign.",
      "type": ["auto", "always", "exceptZero", "negative", "never"],
      "status": "optional"
    },
    "compact": {
      "doc": "Shortens any number or currency including an abbreviation. You can combine `compact` with `currency`. It gives you zero decimal by default `decimals={0}`. Use either `short` or `long`. Defaults to `short` if `true` is given.",
      "type": ["boolean", "string"],
      "status": "optional"
    },
    "prefix": {
      "doc": "Add a string or React component before the number, including white space.",
      "type": "React.Node",
      "status": "optional"
    },
    "suffix": {
      "doc": "Appends a string or React component after the number, including white space. When the suffix is a string starting with `/`, no space is added (e.g. `suffix=\"/mnd\"` renders \"123/mnd\").",
      "type": "React.ReactNode",
      "status": "optional"
    },
    "locale": {
      "doc": "Use a [2 Letter Language Code](https://www.sitepoint.com/iso-2-letter-language-codes/) or an extended code such as `nb-NO`. Use `auto` to detect the locale from the browser (`navigator.language`). Defaults to the Norwegian locale: `nb-NO`.",
      "type": "string",
      "status": "optional"
    },
    "srLabel": {
      "doc": "Will add a visually hidden label, to give screen reader users the missing context to easier understand what the number represents.",
      "type": "string",
      "status": "optional"
    },
    "skeleton": {
      "doc": "If set to `true`, an overlaying skeleton with animation will be shown.",
      "type": "boolean",
      "status": "optional"
    },
    "options": {
      "doc": "Accepts all [number.toLocaleString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString) or [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) options as an object - can also be a JSON given as the parameter e.g. `options={{ 'minimumFractionDigits': 2 }}`.",
      "type": "object",
      "status": "optional"
    },
    "fontSize": {
      "doc": "Typography size fallback used for both main and auxiliary content. `mainSize` and `auxiliarySize` override this value. If omitted, default is `large` (`basis` when nested inside `Stat.Trend` or `Stat.Info`, unless any size prop is set).",
      "type": [
        "\"x-small\"",
        "\"small\"",
        "\"basis\"",
        "\"medium\"",
        "\"large\"",
        "\"x-large\"",
        "\"xx-large\""
      ],
      "status": "optional"
    },
    "mainSize": {
      "doc": "Typography size for the main content. When omitted, it falls back to `fontSize` if provided.",
      "type": [
        "\"x-small\"",
        "\"small\"",
        "\"basis\"",
        "\"medium\"",
        "\"large\"",
        "\"x-large\"",
        "\"xx-large\""
      ],
      "defaultValue": "large (`basis` when nested inside `Stat.Trend` or `Stat.Info`, unless `fontSize`, `mainSize`, or `auxiliarySize` is set)",
      "status": "optional"
    },
    "mainWeight": {
      "doc": "Typography weight for the main content.",
      "type": ["\"regular\"", "\"medium\""],
      "defaultValue": "medium",
      "status": "optional"
    },
    "auxiliaryWeight": {
      "doc": "Typography weight for secondary content like currency sign and affixes. If omitted, and `mainSize` equals `auxiliarySize` while `mainWeight` is omitted, `medium` is used.",
      "type": ["\"regular\"", "\"medium\""],
      "status": "optional"
    },
    "auxiliarySize": {
      "doc": "Typography size for secondary content like currency sign and affixes (`prefix` and `suffix`). When omitted, it falls back to `fontSize` if provided.",
      "type": [
        "\"x-small\"",
        "\"small\"",
        "\"basis\"",
        "\"medium\"",
        "\"large\"",
        "\"x-large\"",
        "\"xx-large\""
      ],
      "defaultValue": "large (`basis` when nested inside `Stat.Trend` or `Stat.Info`, unless `fontSize`, `mainSize`, or `auxiliarySize` is set)",
      "status": "optional"
    },
    "colorizeBySign": {
      "doc": "If `true`, text color follows sign tone (`+` green, `-` red).",
      "type": ["boolean"],
      "defaultValue": "false",
      "status": "optional"
    },
    "[Space](/uilib/layout/space/properties)": {
      "doc": "Spacing properties like `top` or `bottom` are supported.",
      "type": ["string", "object"],
      "status": "optional"
    }
  }
}
```

## Stat.Trend

<PropertiesTable props={TrendProperties} />

## Stat.Rating

<PropertiesTable props={RatingProperties} />

## Stat.Info

<PropertiesTable props={InfoProperties} />

## Stat.Root

<PropertiesTable props={RootProperties} />

## Stat.Label

<PropertiesTable props={LabelProperties} />

## Stat.Content

<PropertiesTable props={ContentProperties} />

## Stat.Inline

```json
{
  "props": {
    "children": {
      "doc": "Inline layout container for content elements, typically `Stat.Trend` and `Stat.Info`.",
      "type": ["React.ReactNode"],
      "status": "optional"
    },
    "skeleton": {
      "doc": "Applies skeleton state to the inline container.",
      "type": "boolean",
      "status": "optional"
    },
    "[Flex.Horizontal](/uilib/layout/flex/horizontal/properties)": {
      "doc": "Supports all additional `Flex.Horizontal` properties.",
      "type": "Various",
      "status": "optional"
    }
  }
}
```

## Stat.Text

<PropertiesTable props={TextProperties} />

## Translations

```json
{
  "locales": ["da-DK", "en-GB", "nb-NO", "sv-SE"],
  "entries": {
    "Stat.rating": {
      "nb-NO": "%value av %max",
      "en-GB": "%value of %max",
      "sv-SE": "%value av %max",
      "da-DK": "%value af %max"
    }
  }
}
```
