PixelProgress

Determinate or indeterminate progress bar that renders as 10 segmented HP-bar blocks on the pixel surface and a smooth filled track on the linear surface.

  • Pixel surface renders an RPG-style 10-segment HP bar; linear surface renders a smooth filled track
  • Seven tones via the shared toneMap palette
  • Optional label + auto-rendered percentage, both individually toggleable
  • Indeterminate mode for unknown-duration work (visual pulse + aria-busy)
  • Input value is safely clamped to the [0, 100] range
Status
stable
Category
feedback
Since
v1.0.0

API

import { PixelProgress } from '@pxlkit/ui-kit';
PropTypeDefaultDescription
value (required)number—Current value 0-100 (clamped).
tone'green' | 'cyan' | 'gold' | 'red' | 'purple' | 'pink' | 'neutral''green'Tone determines fill color. Defaults to 'green'.
labelstring—Optional label rendered above the bar. Also used as the progressbar's accessible name; falls back to "Progress" when omitted.
showValuebooleantrueWhether to show the numeric percentage on the right. Defaults to true.
surface'pixel' | 'linear'—Surface override; falls back to nearest provider.
indeterminatebooleanfalseUnknown-duration work: the bar pulses (it holds still, at 70 %, for a reader who prefers reduced motion), aria-valuenow is dropped and aria-busy set.

ref points to <div>.

Accessibility

WCAG target: 2.1 AA

  • progressbar

Exposes role="progressbar" with aria-valuemin=0 and aria-valuemax=100; aria-valuenow is set from the clamped value. The label prop is forwarded to aria-label, falling back to "Progress" when omitted so the progressbar always has an accessible name. In indeterminate mode aria-valuenow is omitted and aria-busy is set to true so assistive tech announces unknown-duration work; the bar pulses only for a reader who allows motion, and under prefers-reduced-motion: reduce holds still at 70 % opacity. The 10-segment pixel surface is purely visual — assistive tech reads the same progressbar attributes as the linear surface.

Usage

import { PixelProgress } from '@pxlkit/ui-kit';

export function Default() {
  return <PixelProgress value={60} label="HP" />;
}

Examples

Default

import { PixelProgress } from '@pxlkit/ui-kit';

export function Default() {
  return <PixelProgress value={60} label="HP" />;
}

Tones

import { PixelProgress } from '@pxlkit/ui-kit';

export function Tones() {
  return (
    <div className="space-y-3">
      <PixelProgress value={70} tone="neutral" label="Neutral" />
      <PixelProgress value={70} tone="green" label="Green" />
      <PixelProgress value={70} tone="cyan" label="Cyan" />
      <PixelProgress value={70} tone="gold" label="Gold" />
      <PixelProgress value={70} tone="red" label="Red" />
      <PixelProgress value={70} tone="purple" label="Purple" />
      <PixelProgress value={70} tone="pink" label="Pink" />
    </div>
  );
}

Surfaces

import { PixelProgress } from '@pxlkit/ui-kit';

export function Surfaces() {
  return (
    <div className="space-y-4">
      <PixelProgress value={55} label="Pixel (segmented)" surface="pixel" />
      <PixelProgress value={55} label="Linear (smooth)" surface="linear" />
    </div>
  );
}

Without value

import { PixelProgress } from '@pxlkit/ui-kit';

export function WithoutValue() {
  return <PixelProgress value={45} label="Loading assets" showValue={false} />;
}

Without label

import { PixelProgress } from '@pxlkit/ui-kit';

export function WithoutLabel() {
  return <PixelProgress value={80} />;
}

Indeterminate

import { PixelProgress } from '@pxlkit/ui-kit';

export function Indeterminate() {
  return <PixelProgress value={0} label="Working…" indeterminate />;
}

Clamped

import { PixelProgress } from '@pxlkit/ui-kit';

export function Clamped() {
  return (
    <div className="space-y-3">
      <PixelProgress value={-25} label="Below 0 (clamped to 0)" />
      <PixelProgress value={150} label="Above 100 (clamped to 100)" />
    </div>
  );
}

Steps

import { PixelProgress } from '@pxlkit/ui-kit';

export function Steps() {
  return (
    <div className="space-y-3">
      <PixelProgress value={0} label="0%" />
      <PixelProgress value={25} label="25%" />
      <PixelProgress value={50} label="50%" />
      <PixelProgress value={75} label="75%" />
      <PixelProgress value={100} label="100%" />
    </div>
  );
}

Related