Progress

The Progress component displays the completion progress of a task or process. Supports different variants, colors, and animations.

Basics

Track a single completion percentage. Set transitionDuration so the bar animates its width whenever value changes instead of snapping to it.

Loading demo…

import { useState } from 'react'; import { Block, Button, Progress } from '@plocks/ui'; export function Demo() { const [value, setValue] = useState(50); return ( <Block fullWidth> <Progress value={value} transitionDuration={400} /> <Button onPress={() => setValue(Math.round(Math.random() * 100))}>Randomize value</Button> </Block> ); }

Label and description

Progress takes the same field props as the input components: label, description (the sublabel beneath it), error, required, and labelPosition. The block renders outside the track — use Progress.Label for text drawn inside a filled section.

Loading demo…

import { Block, Progress } from '@plocks/ui'; export function Demo() { return ( <Block gap="lg" fullWidth> <Progress value={64} label="Uploading assets" description="12 of 18 files" /> <Progress value={40} color="error" label="Sync" description="Retries every 30 seconds" error="Connection lost — retrying" /> <Progress value={82} label="Storage" required labelPosition="left" color="success" /> <Progress.Root label="Disk usage" description="Documents, photos, and system files"> <Progress.Section value={35} color="primary" /> <Progress.Section value={28} color="success" /> <Progress.Section value={12} color="warning" /> </Progress.Root> </Block> ); }

Advanced

Combine striped and animate to represent indeterminate work.

Loading demo…

import { Block, Progress } from '@plocks/ui'; export function Demo() { return ( <Block fullWidth> <Progress value={100} striped animate /> </Block> ); }

Compound sections

Compose a multi-part bar from Progress.Root, Progress.Section, and Progress.Label. Each section is sized as a percentage of the track, so sections may sum to less than 100% and leave the remainder unfilled.

Loading demo…

import { Block, Progress } from '@plocks/ui'; export function Demo() { return ( <Block fullWidth> <Progress.Root> <Progress.Section value={35} color="primary"> <Progress.Label>Docs</Progress.Label> </Progress.Section> <Progress.Section value={28} color="success"> <Progress.Label>Media</Progress.Label> </Progress.Section> <Progress.Section value={15} color="warning"> <Progress.Label>Other</Progress.Label> </Progress.Section> </Progress.Root> </Block> ); }

With tooltips

Loading demo…

import { Block, Progress } from '@plocks/ui'; const SECTIONS = [ { label: 'Documents', value: 34, color: 'primary' as const }, { label: 'Photos', value: 26, color: 'success' as const }, { label: 'Backups', value: 18, color: 'warning' as const } ]; export function Demo() { return ( <Block fullWidth> <Progress.Root> {SECTIONS.map((section) => ( <Progress.Section key={section.label} value={section.value} color={section.color} tooltip={`${section.label} — ${section.value}%`} /> ))} </Progress.Root> </Block> ); }

Example — segments with legend

Custom-colored segments with tooltips and legend.

Loading demo…

import { Block, ColorSwatch, Progress, Row, Text } from '@plocks/ui'; const USAGE = [ { label: 'Documents', value: 32, color: '#4c6ef5' }, { label: 'Music', value: 24, color: '#12b886' }, { label: 'Code', value: 14, color: '#fab005' }, { label: 'Video Games', value: 9, color: '#fa5252' } ]; const TOTAL_GB = 500; const formatSize = (percent: number) => { const gb = (percent / 100) * TOTAL_GB; return gb < 1 ? `${Math.round(gb * 1024)} MB` : `${Math.round(gb)} GB`; }; export function Demo() { return ( <Block gap="md" fullWidth> <Progress.Root size="lg" radius="xl"> {USAGE.map((segment) => ( <Progress.Section key={segment.label} value={segment.value} color={segment.color} tooltip={{ label: `${segment.label} — ${formatSize(segment.value)} (${segment.value}%)`, withArrow: true }} > <Progress.Label>{formatSize(segment.value)}</Progress.Label> </Progress.Section> ))} </Progress.Root> <Block gap="lg" direction="row" justify="center"> {USAGE.map((segment) => ( <Row key={segment.label} gap="xs" align="center"> <ColorSwatch color={segment.color} size={12} /> <Text variant="small">{segment.label}</Text> <Text variant="small" c="muted"> {segment.value}% </Text> </Row> ))} </Block> </Block> ); }

Vertical orientation

Set orientation="vertical" to fill from the bottom up. Vertical bars have no intrinsic length, so they default to 160 — use length (or h) to size them.

Loading demo…

import { Block, Progress, Row, Text } from '@plocks/ui'; const CHANNELS = [ { label: 'Kick', value: 82 }, { label: 'Snare', value: 64 }, { label: 'Bass', value: 91 }, { label: 'Vox', value: 47 } ]; export function Demo() { return ( <Row gap="md"> {CHANNELS.map((channel) => ( <Block key={channel.label} gap="xs" align="center"> <Progress value={channel.value} orientation="vertical" length={120} /> <Text variant="small" c="muted"> {channel.label} </Text> </Block> ))} </Row> ); }
Scan to open this page on your phoneplocks.dev/ui/Progress