Source: https://monarchui.dev/components/progress-bar/

Components · Data display

# Progress

Linear progress, quota meters and stacked segments.

@rookcom/monarch-react

Component

## Determinate and indeterminate

## Usage examples

### Quota meter

### Segmented

## Purpose

Shows how far a task has got (uploads, syncs, imports), or that it is running when the amount is unknown.

### Use when

- A task reports progress as a number (`value`).
- A long task runs with unknown duration (omit `value`).
- A measured quantity within a range, such as storage, seats or capacity (`semantics="meter"`).
- Parts of one total, such as done / in review / in progress (`segments`).

### Avoid when

- A short wait inside a control: use Spinner.
- Placeholder content while a page loads: use Skeleton or LoadingState.

## Design principles

- Always named: give `label` (or `aria-labelledby`) so the bar says what is progressing.
- Omitting `value` means indeterminate; never fake a moving value.
- Progress is a task; a meter is a measurement. Choose the role that says which.
- Colour reinforces state (warning, over the limit) but the value text always says it too.

## API reference

```tsx
import { Progress } from '@rookcom/monarch-react';
```

| Export | Kind | Rendering | Root class |
| --- | --- | --- | --- |
| `Progress` | component | server-safe | `.mn-progress` |

The default progress bar is built on `@radix-ui/react-progress`; meters and segmented bars render their own `<div>` with the same `mn-progress` classes. The ref is forwarded to the root element in every form.

Types `ProgressTone`, `ProgressSegment` and `ProgressSegmentTone` are exported.

Generated from the TypeScript declarations of `packages/react/src/components/data-display/progress-bar`.

## Properties

`value` is clamped to 0–100% of `max` for the bar width.

For meters, `aria-valuenow` is clamped to `max` and the real value is in `aria-valuetext`.

### `Progress`

Linear progress bar; `value` undefined renders an indeterminate animation. Also a quota meter (`semantics="meter"`) and a stacked bar (`segments`).

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |
| `label` | `string` | Accessible name, e.g. "Upload progress". Required unless aria-labelledby is set. |
| `max` | `number` |  |
| `segments` | `ProgressSegment[]` | Stacked parts that add up to the filled amount, e.g. done / in review / in progress. `value` is then the sum of the segments. |
| `semantics` | `"meter" \| "progressbar"` | `progressbar` (default) for a task moving towards completion; `meter` for a measured quantity within a known range, such as a quota or capacity (`role="meter"`). A meter is never indeterminate. |
| `size` | `"sm" \| "md"` |  |
| `thresholds` | `{ warning?: number; danger?: number; }` | Meter only: values at or above which the automatic tone becomes `warning` and `danger`, e.g. `{ warning: 80, danger: 95 }` of 100. |
| `tone` | `ProgressTone` | Fill colour. Default `accent`. With `semantics="meter"` and no tone, the tone is `neutral` (a normal quota is not a status), follows `thresholds`, and a value over `max` is `danger`. |
| `value` | `number \| null` | 0–`max`. Omit for indeterminate. |
| `valueText` | `string` | Text alternative for the value (`aria-valuetext`), e.g. "7.2 of 10 GB used". Default for meters and segmented bars: generated from the values. |

## Variants

| Prop | Values | Description |
| --- | --- | --- |
| `size` | `'sm'``'md'` | Bar height. Default `md`. Exposed as `data-size`. |
| `tone` | `'accent'``'success'``'warning'``'danger'``'neutral'` | Fill colour. Default `accent`. Exposed as `data-tone`. Meters without a tone default to `neutral`, follow `thresholds`, and turn `danger` over the limit. |
| `semantics` | `'progressbar'``'meter'` | ARIA role. Exposed as `data-semantics` on meters and segmented bars. |
| `segments` | `'ProgressSegment[]'` | Stacked parts in order. Segment tones: the five tones plus `info` and `data-1`…`data-5` (default: the data palette in order). |

## States

| State | Exposed as | Behaviour |
| --- | --- | --- |
| Determinate | – | The bar width is `value / max`, clamped to 0–100%. |
| Indeterminate | `data-indeterminate` | Set when `value` is undefined or null; the bar animates and has no `aria-valuenow`. Meters are never indeterminate. |
| Warning and danger | `data-tone` | Meter tone once the value reaches `thresholds.warning` or `thresholds.danger`. |
| Over the limit | `data-over` | Meter value above `max`: full bar, danger tone, “over the limit” in the value text. |
| Segmented | `data-segmented` | Stacked segments; the value is their sum and they never overflow the track. |

## Interaction behaviour

- None. Progress is a read-only indicator.

## Keyboard support

Not interactive, so there is no keyboard behaviour.

## Accessibility

Role

progressbar, or meter with

semantics="meter"

Accessible name

label

becomes

aria-label

; or pass

aria-labelledby

.

- `valueText` sets `aria-valuetext` (“7.2 of 10 GB used”); meters and segmented bars generate one (“Done 8, In review 4 (12 of 20)”) when it is not given.
- Determinate bars expose `aria-valuenow` (from Radix Progress).
- Indeterminate bars omit `aria-valuenow`.
- With reduced motion the indeterminate animation slows to 3s per cycle.

## Responsive behaviour

- No breakpoints: the bar fills its container width.

## Theme support

- Fill and track use Monarch tokens; `accent` follows the product accent. `neutral` (the meter default) uses `--mn-color-text-muted`, so a normal quota never reads as a status.
- Segment colours use the strong intent tokens and the `--mn-color-data-*` palette, separated by a 2px surface-coloured gap.
- Width transitions are removed under reduced motion.

## Do and don't

### Do

- Name every bar with `label`.
- Switch to `tone="success"` or `"danger"` only when the task has finished that way.

### Don't

- Do not animate a determinate value you cannot measure; use the indeterminate form.
- Do not leave `semantics` as `progressbar` for static quantities such as storage used: use `semantics="meter"`.
- Do not rely on segment colours alone: label each segment, and show a legend when the parts matter.

## Related components

- [Spinner](https://monarchui.dev/components/spinner/): Indeterminate progress inside a control.
- [LoadingState](https://monarchui.dev/components/loading-state/): Placeholder for a whole loading region.
- [StackedProportionBar](https://monarchui.dev/components/stacked-proportion-bar/): Planned chart-style bar with a legend for proportions.
- [StatCard](https://monarchui.dev/components/stat-card/): Headline figure that can sit above a meter.

## Dependencies

| Kind | Depends on |
| --- | --- |
| npm packages | `@radix-ui/react-progress``react` |
| Monarch components | None |

## Testing coverage

- Is a labelled progressbar with `aria-valuenow`; indeterminate has none.
- Default markup is unchanged from 0.3; `valueText` sets `aria-valuetext`.
- Meter role, value text, neutral default and threshold tones; an explicit tone wins.
- Over the limit: danger tone, clamped `aria-valuenow`, “over the limit” text, full bar.
- Segments: order, default tones, offsets, generated value text, no overflow.

| Check | Covered |
| --- | --- |
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | None yet |

Tests: `packages/react/src/components/data-display/progress-bar`

## All example code

### Determinate and indeterminate

```tsx
import { Progress } from '@rookcom/monarch-react';

<Progress label="Upload progress" value={40} />
<Progress label="Import progress" value={100} tone="success" size="sm" />
<Progress label="Syncing members" />
```

### Quota meter

```tsx
import { Progress } from '@rookcom/monarch-react';

<Progress
  semantics="meter"
  label="Storage"
  value={4.2}
  max={10}
  valueText="4.2 of 10 GB used"
/>
<Progress
  semantics="meter"
  label="Seats"
  value={46}
  max={50}
  thresholds={{ warning: 40, danger: 50 }}
  valueText="46 of 50 seats"
/>
<Progress
  semantics="meter"
  label="Capacity"
  value={52}
  max={40}
  valueText="52 of 40 hours, overbooked"
/>
```

### Segmented

```tsx
import { Progress } from '@rookcom/monarch-react';

<Progress
  label="Sprint progress"
  max={24}
  segments={[
    { label: 'Done', value: 11, tone: 'success' },
    { label: 'In review', value: 4, tone: 'info' },
    { label: 'In progress', value: 5, tone: 'warning' },
  ]}
/>
<Progress
  semantics="meter"
  label="Logged hours"
  max={40}
  segments={[
    { label: 'Billable', value: 22 },
    { label: 'Internal', value: 9 },
    { label: 'Leave', value: 4 },
  ]}
/>
```
