Primitives
Progress
Bordered track with a signal indicator, plus an indeterminate `busy` sweep and an optional mono label.
● LIVE
"use client";import { Progress } from "@/registry/okibi/ui/progress";export default function ProgressDemo() { return <Progress value={64} className="w-64 max-w-full" />;}npx shadcn@latest add https://okibi.cndr.dev/r/progress.jsonInstallation
Install the theme first, then add the component:
npx shadcn@latest add https://okibi.cndr.dev/r/progress.jsonInstall the required dependencies:
npm install @radix-ui/react-progressCopy the source from the Code tab above into components/ui/progress.tsx. It uses the cn helper and the okibi theme tokens — install the theme first if you haven't.
Usage
import { Progress } from "@/components/ui/progress"
<Progress value={66} />Examples
Busy
Set busy for an indeterminate "channel busy" state — twin signal-rail dash layers sweep in opposite directions and the bar is reported indeterminate (no aria-valuenow). Add a label for a mono readout row above the track.
● LIVE
Uplink // TX
Buffer
import { Progress } from "@/registry/okibi/ui/progress";export default function ProgressBusyDemo() { return ( <div className="flex w-full max-w-md flex-col gap-5"> <Progress busy label="Uplink // TX" /> <Progress value={64} label="Buffer" /> </div> );}API Reference
Progress
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | – | Fill percentage (0–100). |
busy | boolean | false | Indeterminate 'channel busy' sweep instead of a fill. |
busySpeed | number | 0.5 | Relative speed of the indeterminate busy sweep. |
label | string | – | Optional mono label above the track. |
Accessibility
- Built on the Radix
progressbar— a determinatevaluereportsaria-valuenow, so assistive tech announces the percentage. - Pass a
labeland it is auto-wired as the bar's accessible name via a generated id andaria-labelledby, so the gauge announces what is progressing. - Explicit
aria-labeloraria-labelledbyare forwarded to the track and win over thelabelauto-naming — supply one when the bar has no visible label. - In
busymode thevalueis omitted so Radix reports an indeterminate state (noaria-valuenow), and the sweep layers arearia-hidden. - The mono percentage /
··· TXreadout is decorative andaria-hidden; the announced value comes from the bar itself, never that text. - The
busysweep is gated by the global reduced-motion guard, resting at a static row of signal dashes.
Guidelines
Do
- Give every bar an accessible name — pass
label, or anaria-label/aria-labelledbywhen the label lives elsewhere. - Use
busyfor indeterminate, no-known-duration work; reserve a numericvaluefor measurable progress. - Keep
valuein the 0–100 range — it defaults to 0 so the track renders before data lands.
Don't
- Don't ship an unlabeled
Progress— a bare bar has no accessible name and announces nothing useful. - Don't set both
valueandbusy;busydeliberately drops the value to read as indeterminate. - Don't lean on the visible percentage readout for meaning — it's
aria-hiddendecoration.