# Progress bar

A progress bar built from dither cells: any fill texture with a solid leading edge, stacked parts, step segments and an indeterminate comet.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available by appending `.md` to any URL or sending an `Accept: text/markdown` header. The dithercn agent skill, for building any dither on the engine, is at [/.well-known/agent-skills/dithercn/SKILL.md](/.well-known/agent-skills/dithercn/SKILL.md).

<ComponentPreview src="examples/progress-bar-demo.tsx" controls="progressBarControls">
  <ProgressBarDemo />
</ComponentPreview>

## Installation [#installation]

<InstallBlock name="progress-bar" />

## Usage [#usage]

```tsx
import { ProgressBar } from "@/components/dithercn/progress-bar";

export function Upload({ percent }: { percent: number }) {
  return <ProgressBar label="Uploading report.pdf" value={percent} />;
}
```

`value` runs from 0 to `max`, which is 100 unless you set it. The fill sits on a faint track in the same colour. With `fill="gradient"` it is solid at the leading edge and thins out behind it; `dotted`, `hatched` and `solid` fill evenly. Every texture ends in a solid one-cell cap, so the exact value is always readable. The fill grows in on mount and eases between values.

Leave `value` out when you can't measure progress. The bar becomes indeterminate: a comet with a dense head and a dithered tail sweeps across the track.

```tsx
<ProgressBar label="Indexing repository" />
```

## Examples [#examples]

### Usage card [#usage-card]

`parts` stacks several values in one bar, each in its own colour, with a legend underneath. Here storage is split by file type. Build minutes are close to the limit, so that bar uses `color="red"`, `fill="hatched"` and a low bloom.

<ComponentPreview src="examples/progress-bar-usage.tsx">
  <ProgressBarUsage />
</ComponentPreview>

### Upload list [#upload-list]

Three states at `size="lg"`: a finished file in solid green, one in progress, and an indeterminate step while the server transcodes.

<ComponentPreview src="examples/progress-bar-uploads.tsx">
  <ProgressBarUploads />
</ComponentPreview>

### Onboarding steps [#onboarding-steps]

`segments` cuts the bar into blocks a cell apart. With one block per task, three of five tasks fill three blocks.

<ComponentPreview src="examples/progress-bar-steps.tsx">
  <ProgressBarSteps />
</ComponentPreview>

## Props [#props]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` (required) | `string` |  | What is in progress. Shown above the bar and used as its accessible name. |
| `value` | `number \| null` |  | Progress from 0 to max. Leave it out for an indeterminate bar. |
| `parts` | `ProgressPart[]` |  | { label: string; value: number; color?: DitherColor; fill?: FillVariant }, stacked left to right instead of value. |
| `unit` | `string` |  | With parts: shown after each value in the legend, such as " GB". |
| `max` | `number` | `100` | The value that means done, or the capacity for parts. |
| `valueText` | `string` | `The percentage` | Text for the readout and for screen readers. |
| `hideLabel` | `boolean` | `false` | Hide the label and readout visually. Screen readers still get them. |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Bar height: 2, 4 or 6 cells. |
| `fill` | `"gradient" \| "dotted" \| "hatched" \| "solid"` | `"gradient"` | Texture of the fill. Gradient is densest at the leading edge. |
| `color` | `DitherColor` | `"ink"` | Colour of the fill and its track, a palette name or any CSS colour. |
| `bloom` | `"off" \| "low" \| "high"` | `"off"` | Soft glow in the fill's colour. |
| `segments` | `number` |  | Cut the bar into this many blocks a cell apart, for step meters. |
| `animate` | `boolean` | `true` | Grow in on mount and ease between values. |
| `cell` | `number` | `--dither-cell` | Size of one dither cell in CSS pixels. |

## Notes [#notes]

* The root has `role="progressbar"`, is named by the label and reports the value (or `valueText`). An indeterminate bar leaves out the value, as assistive technology expects.
* Width changes ease over 600ms; the comet moves only by transform. With reduced motion the fill jumps to its value and the comet rests in the middle of the track.
* It is plain HTML with CSS masks: no SVG, canvas or animation loop.