Skip to content

Progress

Show how far a task has progressed, or that work is still running.

import { Progress, ProgressIndicator, ProgressLabel, ProgressTrack, ProgressValue } from '@youj/react'

Installation & usage

npm i @youj/react

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use Progress for measurable work, such as an upload or migration. Pass value={null} when progress is not yet known. Use a Spinner for short, unmeasured waits, or a Slider for values people adjust themselves.

import { Progress, ProgressLabel, ProgressValue } from '@youj/react'

export function Upload({ percent }: { percent: number }) {
  return (
    <Progress value={percent}>
      <ProgressLabel>Uploading hero@2x.png</ProgressLabel>
      <ProgressValue />
    </Progress>
  )
}

Progress renders the track and the bar for you. Put a ProgressLabel and a ProgressValue inside it: they share the first line, and the track wraps below them. Without a visible label, give Progress an aria-label.

Reference

Propstone, variant, size, ticks (4)

Props

Progress

Progress props
PropType
toneProgressTone
'accent''neutral''success''warning''danger'

The fill. Unset, the component style decides: the accent in Classic, a neutral ink in Bezel (which keeps the accent for emphasis). A tone pins it in every style.

–
variant'default' | 'ticks'

ticks draws the track as a row of fine vertical ticks that light from the start.

default 'default'

'default'
sizeExtract<Size, 'sm' | 'default' | 'lg'>

The track's height: the bar's thickness, or the ticks' length.

default 'default'

'default'
ticksnumber

How many ticks the ticks variant draws.

default 40

40
Other props pass through: extends ProgressPrimitive.Root.Props.

It takes Base UI's value (a number, or null for indeterminate), min, max, format, locale and getAriaValueText.

Data attributeValues
data-variantdefault, ticks
data-sizesm, default, lg
data-toneaccent, neutral, success, warning, danger (unset: the style decides)
data-indeterminate, data-progressing, data-completeBase UI's state

ProgressValue

ProgressValue adds no props of its own. They pass through to ProgressPrimitive.Value.Props.

Its children can be a function of the formatted value and the raw value, (formatted, value) => ReactNode.

MotionValue change, indeterminate sweep · reduced motion

Motion

Motion tokens
MomentTokens
Value changethe bar scales along its length, retargeting mid-glide
spring.smooth

0.36s, bounce 0

0.36s, bounce 0
Indeterminate sweepa 40% band crosses the track, on a loop
duration.deliberateease.standard

560ms · cubic-bezier(0.2, 0, 0, 1) · × 2 per sweep

560mscubic-bezier(0.2, 0, 0, 1)× 2 per sweep

Reduced motion

New values jump into place, and the indeterminate band becomes still stripes.

Ticks

Motion tokens
MomentTokens
Value changethe lit count follows the value; the edge tick lights partway and the next three warm up
spring.smooth

0.36s, bounce 0

0.36s, bounce 0
Indeterminate waveeach tick warms quickly and fades slowly, its turn later along the row, so a wave crosses in 70% of the loop and rests
duration.deliberateease.linear

560ms · cubic-bezier(0, 0, 1, 1) · × 2 per loop

560mscubic-bezier(0, 0, 1, 1)× 2 per loop

Reduced motion

The lit count jumps to each value, and indeterminate shows every other tick lit, still.

The ticks only change opacity. They light from the inline start, so under right-to-left they fill and the wave travels from the right.

Bar

The bar stays full width and scales on its X axis, so only transform animates. A burst of updates retargets the spring with its velocity intact instead of restarting a tween, which is why the uneven upload chunks in the demo read as one steady glide. It fills from the inline start, so under right-to-left it fills from the right.

Reduced motion

The bar jumps to each new value instead of gliding, and the indeterminate sweep becomes still diagonal stripes across the track. The ticks light at once, and their indeterminate wave becomes every other tick lit, still. The amount done and the "still working" state both stay visible.

AccessibilityARIA, announcements

Accessibility

  • It's a progressbar with aria-valuenow and a formatted aria-valuetext, named by its ProgressLabel or aria-label.
  • Indeterminate progress has no aria-valuenow, which tells assistive technology the amount isn't known.
  • The ticks are decorative and hidden from assistive tech; the progressbar's value says the same thing.
  • Screen readers don't reliably announce each change. When the work finishes, say so in a polite status, as "All files uploaded." does in the demo.