Progress Bar
ProntoIndicador linear de progresso (determinate ou indeterminate). Comunica % completo de uma operação que tem fim conhecido.
Usar quando
Upload com bytes restantes, importação em lote, processo multi-etapa, instalação. Onboarding com X de Y passos.
Não usar quando
Operação sem progresso medível (use Spinner). Loading curto (use Spinner). Stepper visual (use Stepper component).
Variantes
Microinterações
| Microinteração | Disparada por | Comportamento | Timing |
|---|---|---|---|
| Width transition | value muda | Width 0→target com easing | 500ms cubic-bezier(0.32,0.72,0,1) |
| Indeterminate slide | indeterminate=true | Pílula brass desliza esquerda↔direita continuamente | 1500ms ease loop |
| Complete pulse | value chega a 100 | Bar pisca verde 1x | 300ms ease |
| Reduced motion | prefers-reduced-motion | Sem animação, só width final | instant |
Acessibilidade
Acessibilidade — checklist
ARIA esperado
- role="progressbar"
- aria-valuenow="42" aria-valuemin="0" aria-valuemax="100"
- aria-label="Progresso: 42%"
- Indeterminate: omit aria-valuenow
Notas
- Always include text label visível (não confie só na barra).
- Indeterminate sem aria-valuenow.
- Em mobile: full-width, height 4-6px (não vire ruído).
- Reduced-motion: pular animação de width.
Código
'use client';
import { T, RADIUS } from '@/lib/tokens';
export function ProgressBar({ value, label }: { value: number; label?: string }) {
return (
<div>
{label && <p style={{ fontSize: 12, color: T.ink2, marginBottom: 4 }}>{label}</p>}
<div role="progressbar" aria-valuenow={value} aria-valuemin={0} aria-valuemax={100}
style={{ height: 6, background: T.surface3, borderRadius: 980, overflow: 'hidden' }}>
<div style={{
width: `${value}%`, height: '100%',
background: T.ink, borderRadius: 980,
transition: 'width 500ms cubic-bezier(0.32,0.72,0,1)',
}} />
</div>
</div>
);
}Regras
Faça
- ✓Sempre exiba label textual + % numérico.
- ✓Determinate quando souber bytes/items totais.
- ✓Indeterminate só quando sincronização opaca.
- ✓Height 4-8px (não vire ruído visual).
- ✓Cor padrão ink; success quando complete.
Não faça
- ✗Não use indeterminate quando você SABE o progresso.
- ✗Não use cor brass como default (cor é sinal).
- ✗Não esconda label textual.
- ✗Não force animação rápida (>1500ms = lento, agressivo).
- ✗Não tenha múltiplas progressbars empilhadas (caos).
Tokens usados
| Token | Valor | Papel |
|---|---|---|
T.ink | #0A0A0A | cor da barra preenchida |
T.surface3 | #F3F0E6 | background da track |
T.brass | #A47C2B | indeterminate slider |
T.verde | #2F6B3C | tone=success |
RADIUS.pill | 980 | borderRadius |