# Progress

Shows how far a task has progressed.

Source: [progress.tsx](https://github.com/jakejarvis/jarvis-ui/blob/main/src/components/ui/progress.tsx)

```tsx
import { Progress, ProgressLabel, ProgressValue } from "@/components/ui/progress";

export default function ProgressValues() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-6">
      <Progress value={0}>
        <ProgressLabel>Not started</ProgressLabel>
        <ProgressValue />
      </Progress>
      <Progress value={45}>
        <ProgressLabel>Uploading files</ProgressLabel>
        <ProgressValue />
      </Progress>
      <Progress value={100}>
        <ProgressLabel>Backup complete</ProgressLabel>
        <ProgressValue />
      </Progress>
    </div>
  );
}
```

## Installation

Add the registry, once per project:

```bash
npx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json
```

Then add the component:

```bash
npx shadcn@latest add @jarvis/progress
```

## Usage

```tsx
import { Progress, ProgressLabel, ProgressValue } from "@/components/ui/progress";

export function UploadProgress() {
  return (
    <Progress value={45}>
      <ProgressLabel>Uploading files</ProgressLabel>
      <ProgressValue />
    </Progress>
  );
}
```

`ProgressValue` shows a percentage unless you pass `format` to Progress, or a function as its
children.

## Composition

- `Progress`
  - `ProgressLabel`
  - `ProgressValue`

## Examples

### Indeterminate

Set `value` to `null` when there's no way to tell how far along the task is.

```tsx
import { Progress, ProgressLabel } from "@/components/ui/progress";

export default function ProgressIndeterminate() {
  return (
    <Progress value={null} className="w-full max-w-sm">
      <ProgressLabel>Preparing export…</ProgressLabel>
    </Progress>
  );
}
```

### Without a label

A bare bar needs an `aria-label` to give it an accessible name.

```tsx
import { Progress } from "@/components/ui/progress";

export default function ProgressWithoutLabel() {
  return <Progress value={72} aria-label="Upload progress" className="w-full max-w-sm" />;
}
```

### Live

Update `value` as the task runs.

```tsx
import { UploadIcon } from "lucide-react";
import * as React from "react";

import { Button } from "@/components/ui/button";
import { Progress, ProgressLabel, ProgressValue } from "@/components/ui/progress";

export default function ProgressLive() {
  const [value, setValue] = React.useState<number | null>(null);
  const timer = React.useRef<ReturnType<typeof setInterval>>(undefined);

  React.useEffect(() => () => clearInterval(timer.current), []);

  function start() {
    clearInterval(timer.current);
    setValue(0);
    timer.current = setInterval(() => {
      setValue((prev) => {
        const next = Math.min(100, (prev ?? 0) + 7);
        if (next === 100) clearInterval(timer.current);
        return next;
      });
    }, 200);
  }

  const uploading = value !== null && value < 100;

  return (
    <div className="flex w-full max-w-sm flex-col gap-3">
      <Progress value={value ?? 0}>
        <ProgressLabel>{value === 100 ? "Upload complete" : "design-assets.zip"}</ProgressLabel>
        <ProgressValue />
      </Progress>
      <Button
        variant="secondary"
        size="sm"
        className="self-start"
        onClick={start}
        disabled={uploading}
        focusableWhenDisabled
      >
        <UploadIcon />
        {value === null ? "Start upload" : "Upload again"}
      </Button>
    </div>
  );
}
```

## Props

| Part | Extends |
| --- | --- |
| `Progress` | [`Progress.Root`](https://base-ui.com/react/components/progress#root) |
| `ProgressTrack` | [`Progress.Track`](https://base-ui.com/react/components/progress#track) |
| `ProgressIndicator` | [`Progress.Indicator`](https://base-ui.com/react/components/progress#indicator) |
| `ProgressLabel` | [`Progress.Label`](https://base-ui.com/react/components/progress#label) |
| `ProgressValue` | [`Progress.Value`](https://base-ui.com/react/components/progress#value) |

The tables leave out `className`, `style` and `render`. Parts built on Base UI take them as its [styling](https://base-ui.com/react/handbook/styling) and [composition](https://base-ui.com/react/handbook/composition) guides describe.

### Progress

| Prop                | Type                                                          | Description                                                                                                                                |
| ------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `aria-valuetext?`   | `string`                                                      | A string value that provides a user-friendly name for `aria-valuenow`, the current value of the progress bar.                              |
| `format?`           | `Intl.NumberFormatOptions`                                    | Options to format the value.                                                                                                               |
| `getAriaValueText?` | `((formattedValue: string, value: number \| null) => string)` | Accepts a function which returns a string value that provides a human-readable text alternative for the current value of the progress bar. |
| `locale?`           | `Intl.LocalesArgument`                                        | The locale used by `Intl.NumberFormat` when formatting the value. Defaults to the user's runtime locale.                                   |
| `max?`              | `number`                                                      | The maximum value. Default: `100`                                                                                                          |
| `min?`              | `number`                                                      | The minimum value. Default: `0`                                                                                                            |
| `value`             | `number \| null`                                              | The current value. The component is indeterminate when value is `null`.                                                                    |

### ProgressValue

| Prop        | Type                                                                                   | Description |
| ----------- | -------------------------------------------------------------------------------------- | ----------- |
| `children?` | `((formattedValue: string \| null, value: number \| null) => React.ReactNode) \| null` |             |
