Progress
Linear bars and SVG rings for communicating async progress.
The classes only draw the bar. Give the .nf-progress (or .nf-progress-ring) element role="progressbar", an accessible name (aria-label or aria-labelledby), and aria-valuenow/aria-valuemin/aria-valuemax, updated together with the bar width. Omit aria-valuenow while indeterminate.
Bar
DEFAULT
<div class="nf-progress" role="progressbar" aria-valuenow="65" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">
<div class="nf-progress-bar" style="width: 65%;"></div>
</div>Sizes
SM / DEFAULT / LG
<div class="nf-progress nf-progress-sm" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">
<div class="nf-progress-bar" style="width: 40%;"></div>
</div>
<div class="nf-progress" role="progressbar" aria-valuenow="65" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">
<div class="nf-progress-bar" style="width: 65%;"></div>
</div>
<div class="nf-progress nf-progress-lg" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">
<div class="nf-progress-bar" style="width: 80%;"></div>
</div>Color variants
PRIMARY / SECONDARY / TERTIARY / ERROR
<div class="nf-progress" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">
<div class="nf-progress-bar" style="width: 75%;"></div>
</div>
<div class="nf-progress nf-progress-secondary" role="progressbar" aria-valuenow="55" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">
<div class="nf-progress-bar" style="width: 55%;"></div>
</div>
<div class="nf-progress nf-progress-tertiary" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">
<div class="nf-progress-bar" style="width: 40%;"></div>
</div>
<div class="nf-progress nf-progress-error" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">
<div class="nf-progress-bar" style="width: 20%;"></div>
</div>Indeterminate
INDETERMINATE
<div class="nf-progress nf-progress-indeterminate" role="progressbar" aria-label="Loading">
<div class="nf-progress-bar"></div>
</div>Labeled
WITH PERCENTAGE
72%
<div class="nf-progress-labeled">
<div class="nf-progress" role="progressbar" aria-valuenow="72" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">
<div class="nf-progress-bar" style="width: 72%;"></div>
</div>
<span class="nf-progress-value">72%</span>
</div>Ring
SVG ring controlled by --nf-ring-progress (0–100). Use pathLength="100" on the fill circle so dash lengths map directly to percentages, with r="14" leaving room for the stroke inside the viewBox. Update the visible label and aria-valuenow alongside the CSS value:
PROGRESS RING
75%
<div class="nf-progress-ring" style="--nf-ring-progress: 75; --nf-ring-size: 4rem;" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" aria-label="Sync progress">
<svg viewBox="0 0 32 32" aria-hidden="true">
<circle class="nf-ring-track" cx="16" cy="16" r="14" />
<circle class="nf-ring-fill" pathLength="100" cx="16" cy="16" r="14" />
</svg>
<span class="nf-ring-label">75%</span>
</div>Class reference
| Class | Description |
|---|---|
nf-progress |
Bar track — default 4px height |
nf-progress-bar |
Filled portion — set width inline |
nf-progress-sm |
2px height |
nf-progress-lg |
8px height |
nf-progress-secondary |
Magenta bar |
nf-progress-tertiary |
Tertiary bar |
nf-progress-error |
Error bar |
nf-progress-indeterminate |
Sliding animation — no width needed |
nf-progress-labeled |
Flex wrapper for bar + value text |
nf-progress-value |
Percentage label inside .nf-progress-labeled |
nf-progress-ring |
SVG ring container — set --nf-ring-progress (0–100) |
nf-ring-track |
SVG <circle> — background ring |
nf-ring-fill |
SVG <circle> — filled arc |
nf-ring-label |
Center text label |