Progress
Shows task progress as a linear bar or circular ring.
Playground
<script lang="ts">
import { Progress } from '@urbicon-ui/blocks';
let value = $state(65);
</script>
<Progress
{value}
showValue
/>01 Purpose
A progress indicator reports how far a task has advanced. Give it a value for determinate progress. The
scale runs from 0 to max, which defaults to 100, so a
percentage works on its own and passing max counts in
bytes, steps or any other unit. Omit value for a task that
is running but whose duration you cannot predict.
| Indicator | Reach for it when |
|---|---|
| Progress (determinate) | You can measure how far along a task is: bytes uploaded, steps done, a percentage. |
| Progress (indeterminate) | A task is running in place but its duration is unknown, and a labelled bar fits the layout. |
| Spinner | The wait is short and unmeasured, and a bar would overstate the precision. |
| Skeleton | Content itself is loading and you can hint at its shape in place. |
02 Examples
File upload
label and showValue render their own header row above the track, so a file name and a byte count need no markup of your own. striped animated reads as an active transfer, and it settles to a solid success bar on completion.<div
class="border-border-subtle bg-surface-elevated w-full max-w-md space-y-3 rounded-2xl border p-5"
>
<Progress
value={uploadedMb}
max={totalMb}
label="project-assets.zip"
showValue
formatValue={(v, m) => `${v.toFixed(1)} MB / ${m} MB`}
intent={uploadedMb >= totalMb ? 'success' : 'primary'}
size="sm"
striped={uploading}
animated={uploading}
/>
<Button variant="outlined" size="sm" onclick={simulateUpload} disabled={uploading}>
{uploadButtonLabel}
</Button>
</div>Indeterminate
value when a task is running but its duration is unknown. The bar loops until the work resolves. Always pass a label so the announcement is meaningful.Please keep this window open.
<div class="border-border-subtle bg-surface-elevated w-full max-w-md rounded-2xl border p-5">
<Progress label="Processing payment…" intent="primary" size="sm" />
<p class="text-text-tertiary mt-3 text-xs">Please keep this window open.</p>
</div>Custom value format
showValue to print the percentage. formatValue replaces it with other units, like step counters or storage limits.<Progress
value={3}
max={5}
label="Onboarding"
showValue
formatValue={(v, m) => `${v} of ${m} steps`}
/>
<Progress
value={750}
max={1000}
intent="warning"
label="Storage"
showValue
formatValue={(v) => `${v} MB`}
/>Circular metrics
shape=circular renders a ring with the value in its centre, and size sets the diameter. A ring draws no visible label, so label names it for screen readers while the caption below it is your own markup.<div class="flex gap-8">
<div class="flex flex-col items-center gap-2">
<Progress
value={92}
shape="circular"
intent="success"
label="Uptime"
showValue
size="lg"
/>
<span class="text-text-secondary text-xs font-medium">Uptime</span>
</div>
<div class="flex flex-col items-center gap-2">
<Progress value={67} shape="circular" intent="warning" label="CPU" showValue size="lg" />
<span class="text-text-secondary text-xs font-medium">CPU</span>
</div>
<div class="flex flex-col items-center gap-2">
<Progress
value={34}
shape="circular"
intent="primary"
label="Memory"
showValue
size="lg"
/>
<span class="text-text-secondary text-xs font-medium">Memory</span>
</div>
</div>03 Customization
Pill meter
class reaches the root wrapper, so a track restyle goes through slotClasses. Track and fill take their height from size, which means an override has to reach both or the fill sits short of the track.<Progress
value={72}
intent="primary"
label="Storage used"
showValue
slotClasses={{
track: 'h-3 rounded-full bg-primary/10',
fill: 'h-3 rounded-full'
}}
/>This is one of five ways to restyle a block. See Customization for class, slotClasses, unstyled, preset and provider-level overrides.
04 Accessibility
ARIA progressbar
Renders with role="progressbar" and aria-valuemin / aria-valuemax. In determinate mode it adds aria-valuenow. In indeterminate mode aria-valuenow is omitted to signal that progress is unknown.
Label
The label prop becomes the aria-label on the progressbar. On a linear bar it
also renders as visible text above the track. A ring draws no label, so give it a caption of
your own next to the label. Leave the prop off and
the announcement falls back to the translated word for progress, which names no task, so an
indeterminate bar in particular needs one.
Reduced motion
Under prefers-reduced-motion the striped and indeterminate
linear animations stop, and the width transition collapses to an instant update.
05 API Reference
20 propsProp | Type | Default | Description | |
|---|---|---|---|---|
animated | boolean | false | Animate the striped pattern. Requires striped to be true. | |
circularSize | number | 80 | Diameter of the circular indicator in pixels. | |
class | string | — | Extra classes merged onto the root wrapper element. | |
formatValue | (value: number, max: number) => string | (v, max) => `${Math.round((v/max) * 100)}%` | Format function for the displayed value. | |
indeterminate variant | true | false | Controls the indeterminate behavior and appearance of the Progress component. Available options: true. | |
intent variant | dangerneutralprimarysecondary +2 more | primary | Controls the color theme and semantic meaning of the Progress. Affects the overall appearance and user perception. Available options: danger, neutral, primary, and 3 more. | |
label | string | — | Text label displayed above or inside the progress indicator. | |
max | number | 100 | Maximum value for the progress range. | |
min | number | 0 | Minimum value for the progress range. | |
preset | string | — | Apply a named preset registered via <BlocksProvider presets={{ Progress: {...} }}>.
Prefer this over class overrides when the requested look falls outside the
semantic intent palette — presets keep hover/active/dark-mode logic coherent
and make the custom look reusable across the project. | |
shape | linearcircular | 'linear' | Shape of the progress indicator. | |
showValue | boolean | false | Show the numeric value (percentage or absolute) next to the label. | |
size variant | lgmdsmxs | md | Controls the dimensions, padding, and text size of the Progress. Affects the component's physical footprint. Available options: lg, md, sm, xs. | |
slotClasses | Partial<Record<ProgressSlots, string>> | — | Per-slot class overrides merged with tv() styles. Slots: wrapper (linear
root — what class targets in linear shape) | header | label | valueText |
track | fill | circularWrapper (circular root — what class targets in
circular shape) | circularTrack | circularFill | circularLabel. | |
striped | boolean | false | Display striped pattern on the fill. | |
strokeWidth | number | 6 | Stroke width of the circular indicator in pixels. | |
unstyled | boolean | — | Remove all default tv() classes. | |
value | number | — | Current progress value (0–100). Omit for indeterminate mode. | |
...HTMLAttributes<HTMLDivElement> inherited | HTMLAttributes | — | HTML attributes (excluding: 'children' | 'class') | |
...ProgressVariants variant | VariantProps | — | Styling variants from ProgressVariants |
06 Types
Local type definitions used by this component.
Name | Kind | Category | Used by | Description | |
|---|---|---|---|---|---|
ProgressProps | interface | props | 0 | — | |
ProgressVariants | type | variant | 1 | — | |
ProgressSlots | type | variant | 0 | Slot names derived from the tv() config above — single source of truth for slotClasses. |
07 Installation
Import
import { Progress } from '@urbicon-ui/blocks';