```tsx
import * as Progress from '@gentleduck/primitives/progress'
```

## Anatomy

```tsx
<Progress.Root>
  <Progress.Indicator />
</Progress.Root>
```

## Example

```tsx
<Progress.Root
  className="relative h-4 w-full overflow-hidden rounded-full bg-gray-200"
  value={65}
  max={100}
>
  <Progress.Indicator
    className="h-full bg-blue-500 transition-all"
    style={{ width: `${65}%` }}
  />
</Progress.Root>
```

## API

### `Progress.Root`

Renders a `<div>` with `role="progressbar"` and appropriate ARIA attributes.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `number \| null` | `null` | Current value. `null` = indeterminate. |
| `max` | `number` | `100` | Maximum value |
| `getValueLabel` | `(value: number, max: number) => string` | Percentage | Custom label for screen readers |
| `dir` | `'ltr' \| 'rtl'` | - | Reading direction |

Exposes `data-state` as `indeterminate`, `loading`, or `complete`, and `data-value` / `data-max`.

### `Progress.Indicator`

Visual fill indicator. Inherits `data-state`, `data-value`, and `data-max` from context.

## Indeterminate state

}>
  Pass `value={null}` for an indeterminate progress bar. The `data-state` will be set to `indeterminate`, which you can target in CSS for a loading animation.

```tsx
<Progress.Root value={null} className="relative h-4 w-full overflow-hidden rounded-full bg-gray-200">
  <Progress.Indicator className="h-full bg-blue-500 animate-indeterminate" />
</Progress.Root>
```

```css
@keyframes indeterminate {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(400%); }
}
.animate-indeterminate {
  width: 30%;
  animation: indeterminate 1.5s ease-in-out infinite;
}
```