<!-- Protocore Design System — NProgress -->
# NProgress

- **Category:** Feedback (`feedback`)
- **Slug:** `feedback/nprogress`
- **Status:** stable
- **Platforms:** web
- **Import:** `import { NProgress, nprogress } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/feedback/nprogress

> A thin top-of-viewport progress bar with an imperative start/done controller for route and async transitions.

## When to use it

This is the ambient "something is loading" signal for whole-page transitions: a client-side route change, a server action, a slow navigation. The trickle communicates ongoing work without a known duration — you call `start()` when the transition begins and `done()` when it ends, and the bar handles the in-between.

Because the controller is a module-level singleton, call it from anywhere — a router event, a fetch wrapper, a mutation callback — without threading props. For determinate work with a real percentage, use **ProgressBar**; for a small in-place action, use **InlineLoading**.

## Props

### NProgress

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `className` | `string` | no | — | — |
| `height` | `number` | no | `2` | Bar height in px. |
| `label` | `string` | no | `Page loading` | Accessible name for the progressbar. |
| `style` | `CSSProperties` | no | — | — |

### nprogress

_No documented props._

## Examples

### Driving the bar

Mount `<NProgress />` once near your app root, then drive it with the `nprogress` controller. `start()` shows the bar and trickles it upward toward — but never reaching — 100%; `done()` fills and fades it out. `set()` and `increment()` give you manual control.

```tsx
import * as React from "react";
import { NProgress, nprogress, Button, Group } from "@protocore/pds";

export default function NProgressBasics() {
  // Tidy up any pending trickle when the demo unmounts.
  React.useEffect(() => () => nprogress.reset(), []);

  const simulate = () => {
    nprogress.start();
    window.setTimeout(() => nprogress.done(), 1600);
  };

  return (
    <div>
      <NProgress />
      <Group>
        <Button size="sm" onClick={simulate}>
          Simulate navigation
        </Button>
        <Button size="sm" variant="secondary" onClick={() => nprogress.start()}>
          Start
        </Button>
        <Button size="sm" variant="secondary" onClick={() => nprogress.set(0.5)}>
          Set 50%
        </Button>
        <Button size="sm" variant="secondary" onClick={() => nprogress.done()}>
          Done
        </Button>
      </Group>
    </div>
  );
}
```

## Usage

**Do**

- Mount exactly one `<NProgress />` near the app root.
- Call `nprogress.start()` on transition start, `done()` on end.
- Wire it to router events or a shared fetch wrapper.
- Let the trickle stand in for an unknown duration.

**Don't**

- Mount several bars; they share one controller and will fight.
- Use it for determinate progress with a real percent — that's ProgressBar.
- Forget the matching `done()`; the bar will trickle forever.

## Accessibility

**Notes**

- The bar is `role="progressbar"` with live `aria-valuenow`, and `aria-hidden` while idle so it isn't announced at rest.
- It is decorative ambient feedback — pair slow transitions with a focus or content change that assistive tech can perceive directly.

## Related

`progress-bar`, `inline-loading`, `loading-overlay`, `spinner`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
