Three separate components live under this one docs entry — CircularProgress, LinearProgress, and WavyLinearProgress (a custom, M3-inspired wavy variant). Each
has its own prop set — they are not interchangeable via a shared "variant" prop — so pick the
component that matches the shape you need.
All three components are built on bits-ui's Progress.Root for the underlying ARIA semantics, and share the same determinate/indeterminate
convention: pass a percent between 0–100 for a determinate
indicator, or omit it (or pass null) for an indeterminate
one.
CircularProgress and LinearProgress map directly to M3's circular and linear progress indicators. WavyLinearProgress is this library's own extra variant —
a sine-wave linear indicator inspired by, but not a literal reproduction of, M3's spec; it
renders raw SVG with the wave path computed by an internal _wavy.ts helper module (not part of the public API).
import { CircularProgress, LinearProgress, WavyLinearProgress } from '@noxlovette/material'; See all three live, with Controls, in Storybook rather than a hand-rolled preview here.
Playground
Determinate and indeterminate stories for Circular, Linear, and Wavy.
<script lang="ts">
import { CircularProgress, LinearProgress, WavyLinearProgress } from '@noxlovette/material';
let uploadPercent = $state(40);
</script>
<!-- Determinate -->
<CircularProgress percent={uploadPercent} />
<LinearProgress percent={uploadPercent} class="w-full" />
<WavyLinearProgress percent={uploadPercent} class="w-full" />
<!-- Indeterminate: omit percent -->
<CircularProgress />
<LinearProgress class="w-full" />
<WavyLinearProgress class="w-full" /> | Prop | Type | Default | Description |
|---|---|---|---|
percent | number | null | — | Completion percentage (0–100). Omit, or pass null, for an indeterminate spinner. |
size | number | 48 | Diameter of the indicator in pixels. |
thickness | number | 4 | Stroke thickness in pixels. |
| Prop | Type | Default | Description |
|---|---|---|---|
percent | number | null | — | Completion percentage (0–100). Omit, or pass null, for an indeterminate bar. |
height | number | 4 | Height of the bar in pixels. |
class | string | — | Additional classes merged onto the track container — use this to set a width (e.g. w-full). |
| Prop | Type | Default | Description |
|---|---|---|---|
percent | number | null | — | Completion percentage (0–100). Omit, or pass null, for an indeterminate line. |
width | number | 600 | Width of the SVG's viewBox. |
height | number | 10 | Height of the SVG's viewBox. |
thickness | number | 4 | Stroke thickness of the wave/track lines. |
class | string | — | Additional classes applied to the SVG element — use this to set a rendered width. |
ARIA semantics via bits-ui
Progress.Root supplies role="progressbar" with aria-valuenow/aria-valuemin/aria-valuemax wired to percent, and omits aria-valuenow automatically for indeterminate state.
Indeterminate still needs a label
None of the three components render visible or accessible text describing what is loading — pair them with your own aria-label or adjacent text for screen reader users.
Motion sensitivity
WavyLinearProgress and indeterminate states rely on continuous animation; consider respecting prefers-reduced-motion in contexts where that matters.