# React Bootstrap Progress Bar

A React Bootstrap progress bar in AdminKit PRO: the width and aria-valuenow from one value, labels, sizes, colors, stripes and stacked bars.

> This component is only available in **AdminKit PRO**. [Learn more](/pricing/#react).

Use a progress bar when you know how far something has come: an upload, a list of tasks, a storage quota. In AdminKit you see them on the project cards, the settings page and the CRM and analytics dashboards.

There is no progress component to import. You write Bootstrap's `.progress` markup in JSX and give it one number from your props or state. That number sets both the width of the bar and its `aria-valuenow`, so what people see and what screen readers announce stay the same. Progress bars are part of the PRO version of [AdminKit for React](/react/).

## Example

```html
<div class="progress" role="progressbar" aria-label="Upload" aria-valuenow="65" aria-valuemin="0" aria-valuemax="100" style="max-width: 24rem;">
  <div class="progress-bar" style="width: 65%"></div>
</div>
```
```tsx code
export function UploadProgress({ value }: { value: number }) {
  return (
    <div
      className="progress"
      role="progressbar"
      aria-label="Upload"
      aria-valuenow={value}
      aria-valuemin={0}
      aria-valuemax={100}
    >
      <div className="progress-bar" style={{ width: `${value}%` }} />
    </div>
  );
}
```

In JSX, the `aria-value*` attributes take numbers and `style` takes an object. That is why the width is a template string: `` style={{ width: `${value}%` }} ``. When the value changes, the bar slides to its new width with Bootstrap's transition.

## Classes

| Class | Effect |
| --- | --- |
| `progress` | The track, 1rem high; it carries `role="progressbar"` and the `aria-value*` attributes |
| `progress-bar` | The filled part; its `width` is the value |
| `progress-sm`, `progress-lg` | AdminKit: a 0.4rem or 1.5rem high track |
| `bg-<color>` | The bar color: `bg-success`, `bg-warning`, ... |
| `progress-bar-striped` | Stripes over the bar color |
| `progress-bar-animated` | Moves the stripes |
| `progress-stacked` | Holds several `.progress` elements as segments of one bar |

## Value from a quota

A quota is rarely a percentage, so you convert it first. The billing card of the settings page shows storage this way. Each bar has a visible label that `aria-labelledby` points to:

```html
<div style="max-width: 24rem;">
  <div class="d-flex justify-content-between mb-1">
    <span id="storage-label">Storage</span>
    <span class="text-body-secondary">18.4 GB of 100 GB</span>
  </div>
  <div class="progress progress-sm" role="progressbar" aria-labelledby="storage-label" aria-valuenow="18" aria-valuemin="0" aria-valuemax="100">
    <div class="progress-bar" style="width: 18%"></div>
  </div>
</div>
```
```tsx code
export function StorageUsage({ used, total }: { used: number; total: number }) {
  const percent = Math.min(Math.round((used / total) * 100), 100);

  return (
    <>
      <div className="d-flex justify-content-between mb-1">
        <span id="storage-label">Storage</span>
        <span className="text-body-secondary">
          {used} GB of {total} GB
        </span>
      </div>
      <div
        className="progress progress-sm"
        role="progressbar"
        aria-labelledby="storage-label"
        aria-valuenow={percent}
        aria-valuemin={0}
        aria-valuemax={100}
      >
        <div className="progress-bar" style={{ width: `${percent}%` }} />
      </div>
    </>
  );
}
```

Clamp the value, as the CRM dashboard does with `Math.min(..., 100)`, so a quota above 100% does not overflow the track.

## Labels, colors and stripes

Text inside `.progress-bar` appears on the bar itself. Keep it short, and only put it on bars that are wide enough to hold it. A `bg-` class changes the color, and the striped classes add stripes that stand still or move:

```html
<div class="progress mb-3" role="progressbar" aria-label="Tasks done" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">
  <div class="progress-bar bg-success" style="width: 25%">25%</div>
</div>
<div class="progress mb-3" role="progressbar" aria-label="Import" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">
  <div class="progress-bar progress-bar-striped" style="width: 50%"></div>
</div>
<div class="progress" role="progressbar" aria-label="Sync" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100">
  <div class="progress-bar progress-bar-striped progress-bar-animated bg-info" style="width: 75%"></div>
</div>
```
```tsx code
<div className="progress" role="progressbar" aria-label="Tasks done" aria-valuenow={25} aria-valuemin={0} aria-valuemax={100}>
  <div className="progress-bar bg-success" style={{ width: "25%" }}>25%</div>
</div>
<div className="progress" role="progressbar" aria-label="Import" aria-valuenow={50} aria-valuemin={0} aria-valuemax={100}>
  <div className="progress-bar progress-bar-striped" style={{ width: "50%" }} />
</div>
<div className="progress" role="progressbar" aria-label="Sync" aria-valuenow={75} aria-valuemin={0} aria-valuemax={100}>
  <div className="progress-bar progress-bar-striped progress-bar-animated bg-info" style={{ width: "75%" }} />
</div>
```

## Stacked bars

When one bar has to show the parts of a whole, such as paid, pending and overdue amounts, stack the parts. Wrap one `.progress` per segment in `.progress-stacked`, and give each its own value and label:

```html
<div class="progress-stacked">
  <div class="progress" role="progressbar" aria-label="Paid" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 45%">
    <div class="progress-bar bg-success"></div>
  </div>
  <div class="progress" role="progressbar" aria-label="Pending" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100" style="width: 30%">
    <div class="progress-bar bg-warning"></div>
  </div>
  <div class="progress" role="progressbar" aria-label="Overdue" aria-valuenow="10" aria-valuemin="0" aria-valuemax="100" style="width: 10%">
    <div class="progress-bar bg-danger"></div>
  </div>
</div>
```
```tsx code
const segments = [
  { label: "Paid", value: 45, color: "success" },
  { label: "Pending", value: 30, color: "warning" },
  { label: "Overdue", value: 10, color: "danger" },
];

<div className="progress-stacked">
  {segments.map((segment) => (
    <div
      key={segment.label}
      className="progress"
      role="progressbar"
      aria-label={segment.label}
      aria-valuenow={segment.value}
      aria-valuemin={0}
      aria-valuemax={100}
      style={{ width: `${segment.value}%` }}
    >
      <div className={`progress-bar bg-${segment.color}`} />
    </div>
  ))}
</div>
```

## Accessibility

- Every bar needs a name: `aria-label`, or `aria-labelledby` pointing at a visible label.
- Keep `aria-valuenow` equal to the width, from the same variable, so screen readers read the value the bar shows.
- When the bar shows a value that is not a percentage, such as 18.4 GB, add `aria-valuetext` with that text.
- A label on the bar must stay readable: AdminKit PRO gives `.progress-bar.bg-warning` dark text, since white text does not reach a 4.5:1 contrast on it.

## Related

- [Next.js Bootstrap progress bar](/nextjs/docs/components/progress/): the same markup in AdminKit for Next.js
- [Bootstrap 5 progress](/bootstrap/docs/components/progress/): the progress bars of the HTML version
- [Spinners](/react/docs/components/spinners/): a loading state without a known value
- [General UI demo](https://react-demo.adminkit.io/ui-general)

---

Canonical HTML page: https://adminkit.io/react/docs/components/progress/

Site overview for agents: https://adminkit.io/llms.txt (expanded: https://adminkit.io/llms-full.txt) · Documentation: https://adminkit.io/bootstrap/docs/ · Questions: support@adminkit.io
