# Progress

A bar for work whose progress is measured: an upload, an import, an index. It moves only between values the service reported, and it starts at the first value it is given rather than filling from empty. With no `value` it is indeterminate: a pulsing bar and the `label` as text, and never a made-up percentage.

- Registry name: `progress` (`@candor/progress`)
- Tier: Free (MIT). No licence key needed.
- Docs: https://candor.themethodic.com/docs/progress

## Install

```bash
npx candor-ui add progress
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/progress`.
It brings in: locale, motion, tokens, utils.
npm packages: @base-ui/react@^1.9.0.

## Example

```tsx
"use client"

import * as React from "react"
import { Progress } from "@/components/candor/ui/progress"

export default function Example() {
  // The bar shows what the service reported, so it moves when a new figure arrives and not before.
  const [done, setDone] = React.useState(12)
  return (
    <div className="flex w-full max-w-sm flex-col gap-6">
      <div className="flex flex-col gap-2">
        <div className="flex items-center justify-between text-sm">
          <span className="font-medium">Importing records</span>
          <span className="tabular-nums text-muted-foreground">{done} of 40</span>
        </div>
        <Progress label="Importing records" value={done} max={40} />
        <button type="button" className="self-start text-xs text-accent-text underline-offset-4 hover:underline" onClick={() => setDone((d) => Math.min(40, d + 7))}>
          Next report from the service
        </button>
      </div>
      <div className="flex flex-col">
        <Progress label="Indexing documents. The total isn't known yet." />
      </div>
    </div>
  )
}
```

## <Progress>

Props:

- `className?: string | undefined`: Classes for the bar's track.
- `value?: number | null | undefined`: How far along the work is, from `0` to `max`, as the service reported it. Leave it out (or pass `null`) when the total isn't known: the bar then shows no fraction, only that work is going on, with the `label`. A bar is a claim about a fraction, so the app never estimates one.
- `max?: number | undefined`: The value that means finished. Defaults to 100.
- `label?: string | undefined`: What is progressing, in the app's words and language ("Indexing 12 files", "Uploading report.pdf"). It names the bar for assistive technology, and when `value` is unknown it is printed under the bar as the word that says so.

Also takes the props of `Omit<ProgressPrimitive.Root.Props, "value" | "max" | "className">`.

## Motion

- **indeterminate** (live): While the total is unknown, the bar pulses (the live family's pulse) and the label shimmers with it; it runs only while that state lasts, and stops the moment a value arrives.
- **value** (fill): The filled part moves to each new measured value in the slow duration, and not on first draw.

Set with `--cd-motion-progress-<moment>-*` in your brand file; the families are in the design reference.

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider`: its fixed strings in `strings`, its nouns in `nouns`; entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
