# Progress

A bar that shows how far a long-running task has advanced.

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

function ProgressDemo() {
  return (
    <Progress value={64} className="w-full max-w-sm">
      <ProgressLabel>Scanning assets</ProgressLabel>
      <ProgressValue />
    </Progress>
  )
}
```

## Usage

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

export function ScanProgress({ value }: { value: number }) {
  return (
    <Progress value={value}>
      <ProgressLabel>Scanning assets</ProgressLabel>
      <ProgressValue />
    </Progress>
  )
}
```

Use a progress bar when a task reports how much of it is done: a scan, an export, an import.
`Progress` renders the track and the indicator itself; its children (a label and a value) go
on a row above the bar.

Use something else when:

- The duration is unknown: use a [Spinner](/components/spinner). This component draws an empty
  track for `value={null}`, so it cannot show an indeterminate state.
- The value is a measurement, not a task, such as storage used or a risk score: a progress
  bar tells screen readers that something is loading.

## Examples

### Without a label

When the label is elsewhere on screen, or the bar sits inside a row that names the task, drop
the children and set `aria-label` on `Progress`.

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

function ProgressWithoutLabel() {
  return (
    <Progress
      value={30}
      aria-label="Report export"
      className="w-full max-w-sm"
    />
  )
}
```

### Custom range and value text

`value` runs from `min` to `max` (0 to 100 by default). `ProgressValue` shows a percentage
unless you pass a function as its child, which receives the formatted and the raw value. Set
`getAriaValueText` to the same text so screen readers hear it too.

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

function ProgressCustomRange() {
  return (
    <Progress
      value={12}
      max={40}
      getAriaValueText={(_, value) => `${value} of 40 domains checked`}
      className="w-full max-w-sm"
    >
      <ProgressLabel>Checking domains</ProgressLabel>
      <ProgressValue>{(_, value) => `${value} of 40`}</ProgressValue>
    </Progress>
  )
}
```

### Updating

The indicator animates between values. Update `value` as the task reports progress; at `max`,
the root gets `data-complete`, which you can use to change the style or swap in a done message.

```tsx
import * as React from "react"
import { Button } from "@zenoxai/ui/components/button"
import { Progress, ProgressLabel, ProgressValue } from "@zenoxai/ui/components/progress"

function ProgressSimulated() {
  const [value, setValue] = React.useState(0)
  const [started, setStarted] = React.useState(false)
  const running = started && value < 100

  React.useEffect(() => {
    if (!running) return
    const timer = setTimeout(() => setValue((current) => current + 10), 400)
    return () => clearTimeout(timer)
  }, [running, value])

  return (
    <div className="flex w-full max-w-sm flex-col items-start gap-4">
      <Progress value={value} className="w-full">
        <ProgressLabel>Exporting incident report</ProgressLabel>
        <ProgressValue />
      </Progress>
      <Button
        variant="outline"
        size="sm"
        disabled={running}
        onClick={() => {
          setValue(0)
          setStarted(true)
        }}
      >
        {value === 100 ? "Export again" : "Start export"}
      </Button>
    </div>
  )
}
```

## Accessibility

- The root renders `role="progressbar"` with `aria-valuenow`, `aria-valuemin` and
  `aria-valuemax`. `ProgressLabel` names it through `aria-labelledby`; without one, set
  `aria-label`.
- Screen readers do not announce every change of the value. When the task ends, announce the
  result separately, with a toast or a `role="status"` message.

## API reference

`import { ... } from "@zenoxai/ui/components/progress"`

### Progress

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| aria-valuetext | `string` |  | A string value that provides a user-friendly name for `aria-valuenow`, the current value of the progress bar. |
| format | `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 | `LocalesArgument` |  | The locale used by `Intl.NumberFormat` when formatting the value. Defaults to the user's runtime locale. |
| max | `number` | `100` | The maximum value. |
| min | `number` | `0` | The minimum value. |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, ProgressRootState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |
| value (required) | `number \| null` |  | The current value. The component is indeterminate when value is `null`. |

### ProgressTrack

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, ProgressTrackState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### ProgressIndicator

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, ProgressIndicatorState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### ProgressLabel

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, ProgressLabelState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### ProgressValue

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, ProgressValueState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

