Gecko UIGecko UI

Progress

How far along something is

Progress

How far along something is.

Installation

import { Progress } from '@geckoui/geckoui';

Basic Usage

40%
<Progress value={40} />
<Progress value={40} label={({ percent }) => `${percent}%`} />

Props API

PropTypeDefaultDescription
valuenumber-How far along. Leave it out when you do not know
maxnumber100What value is measured against
colorkeyof ProgressColorMap'primary'default, primary, success, error, warning or info
sizekeyof ProgressSizeMap'md'sm, md or lg
labelReactNode | ({ percent, value, max }) => ReactNode-Text above the bar
classNamestring-CSS class for the progress
...restHTMLAttributes<HTMLDivElement>-All standard div attributes

Examples

Out of something other than 100

3 of 7 files
<Progress value={3} max={7} label={({ value, max }) => `${value} of ${max} files`} />

value is clamped into range, and the label is handed the clamped number, so it never reports more than the bar shows. percent is rounded to whole numbers and drives the bar width too, so the two never disagree.

When the length is not known

Uploading…
<Progress />
<Progress label="Uploading…" />

Leaving value out runs the bar end to end until you have a number. value={0} is a known value, not an unknown one, so it draws an empty bar.

A label node shows either way. A label function is only called when there is a value to report.

Colours

default
primary
success
error
warning
info
<Progress value={60} color="success" />
<Progress value={60} color="error" />

The colours are the shared semantic tokens, so they match Badge, Alert and Toast.

Sizes

<Progress value={60} size="sm" />
<Progress value={60} size="lg" />

Styling with CSS

VariableDefaultApplies to
--gecko-progress-accentper colorThe bar
--gecko-progress-track--color-surface-hover-strongThe groove behind it
--gecko-progress-heightper sizeBar thickness
--gecko-progress-radius9999pxCorner radius
--gecko-progress-duration1.4sOne cycle when the value is unknown
--gecko-progress-label-gap0.375remSpace between the label and the bar
.GeckoUIProgress {
  --gecko-progress-accent: var(--color-primary-400);
  --gecko-progress-radius: 0.25rem;
}

Class names and data attributes

  • GeckoUIProgress - The progress, with data-size, data-color and data-indeterminate
  • GeckoUIProgress__label - The text above the bar
  • GeckoUIProgress__track - The groove
  • GeckoUIProgress__bar - The filled part

Adding your own colours

Both axes are extensible maps, so you can add keys through module augmentation and style them with CSS. No component change is needed:

declare module '@geckoui/geckoui' {
  interface ProgressColorMap {
    brand: unknown;
  }
}

<Progress value={60} color="brand" />
.GeckoUIProgress[data-color="brand"] {
  --gecko-progress-accent: oklch(0.62 0.21 320);
}

The same works for ProgressSizeMap.

Accessibility

The progress carries role="progressbar" with aria-valuemin, aria-valuemax and aria-valuenow.

While the value is unknown, aria-valuenow is left off entirely. That is what tells a screen reader the value is not known, rather than that nothing has happened yet.

Give it a name with aria-label, or point at your own heading with aria-labelledby:

<Progress value={40} aria-label="Upload" />

Motion

Both the fill and the unknown-length animation are dropped under prefers-reduced-motion. The unknown-length bar becomes a full-width pulse rather than stopping, which would read as stalled work.

  • Spinner - For work with no length to report
  • Skeleton - For content whose shape you know but not its contents