Skip to main content
Gremorie
Feedback

Progress

Barra de progresso horizontal determinada com track e indicator controlados por token.

Visão geral

Progress é o primitive de progresso determinado: uma barra horizontal que preenche de 0 a 100 por cento conforme uma tarefa de longa duração avança. Envolve o Radix Progress para que a semântica subjacente de aria-valuenow, aria-valuemin, aria-valuemax, e role="progressbar" seja tratada para você.

Use Progress quando o percentual concluído é conhecido: uploads com contagem de bytes, formulários multi-step com steps explícitos, batch jobs reportando do servidor. Para durações desconhecidas, recorra ao Skeleton ou a um spinner - mostrar uma barra determinada que não correlaciona de fato com o progresso é pior do que não ter barra nenhuma.

Preview

'use client';import { Progress } from '@gremorie/rx-feedback';import { useEffect, useState } from 'react';export function ProgressPreview() {  const [value, setValue] = useState(13);  useEffect(() => {    const id = setTimeout(() => setValue(72), 500);    return () => clearTimeout(id);  }, []);  return (    <div className="flex max-w-md flex-col gap-3">      <Progress value={value} />      <Progress value={33} />      <Progress value={88} />    </div>  );}

Anatomia

Progress   um track arredondado contendo um indicator preenchido transladado por value%

Instalação

bash npx gremorie@latest add rx-progress
bash pnpm dlx gremorie@latest add rx-progress
bash yarn dlx gremorie@latest add rx-progress
bash bunx --bun gremorie@latest add rx-progress

Uso

import { Progress } from "@gremorie/rx-feedback";

export function UploadProgress({ value }) {
  return (
    <div className="flex flex-col gap-2">
      <div className="flex justify-between text-sm text-muted-foreground">
        <span>Uploading</span>
        <span>{value}%</span>
      </div>
      <Progress value={value} />
    </div>
  );
}
npx gremorie@latest add ng-progress
import { Component, input } from '@angular/core';
import { Progress } from '@gremorie/ng-feedback';

@Component({
  selector: 'app-upload-progress',
  standalone: true,
  imports: [Progress],
  template: `
    <div class="flex flex-col gap-2">
      <div class="flex justify-between text-sm text-muted-foreground">
        <span>Uploading</span>
        <span>{{ value() }}%</span>
      </div>
      <gr-progress [value]="value()" />
    </div>
  `,
})
export class UploadProgressComponent {
  readonly value = input<number>(0);
}

API

<Progress>

A raiz e o indicator juntos. Renderiza um Root do Radix estilizado como um track de 8 px mais um Indicator que translada horizontalmente com base no value. Os slots de track e indicator são expostos via data-slot="progress" e data-slot="progress-indicator".

PropTypeDefaultDescription
valuenumber | null-Valor atual, 0 a 100. Controla a translação do indicator. Defina como null para entrar no estado indeterminado (o indicator para de responder ao value e você assume o controle via uma classe custom).
maxnumber100Limite superior. A maioria dos callers deixa isso em 100 e passa uma porcentagem; passe um max diferente (ex. bytes de arquivo) apenas quando o valor de origem estiver naturalmente nesse range.
getValueLabel(value: number, max: number) => stringpercentagemGerador de label custom para aria-valuetext. Sobrescreva para localizar ("42 percent") ou para expor unidades ("3 of 8 steps").
classNamestring-Aplicado ao track raiz. Sobrescreva a altura com cuidado - 8 px (h-2) combina com o resto da superfície.
...propsReact.ComponentProps<typeof ProgressPrimitive.Root>-Todos os atributos de Root do Radix.

O indicator empacotado é determinado. Para construir uma variant indeterminada, passe value={null} e adicione uma classe custom no indicator (ou faça fork do componente) para animar uma stripe em movimento. Mostrar uma barra indeterminada com um value animado falso é um anti-pattern de tracking-por-ilusão.

Composição

  1. <Progress value={n} /> é o componente inteiro - não há um slot <ProgressIndicator> separado para compor no call site.
  2. Combine com um label: uma barra silenciosa deixa o usuário adivinhando. Monte um pequeno <span> acima ou ao lado dela com a porcentagem, a contagem de steps, ou o progresso em bytes.
  3. Dentro de um Alert ou de um Card: um progress que explica o que está carregando é lido melhor do que um progress que flutua sozinho. Envolva com uma linha de contexto para que os usuários saibam por que estão esperando.

Variações

Labels de valor

Step queued0%
Step 33%33%
Step 66%66%
Step 100%100%
'use client';import { Progress } from '@gremorie/rx-feedback';export function ProgressValuesPreview() {  return (    <div className="flex max-w-md flex-col gap-4">      {[0, 33, 66, 100].map((value) => (        <div key={value} className="flex flex-col gap-2">          <div className="flex justify-between text-sm">            <span>Step {value === 0 ? 'queued' : `${value}%`}</span>            <span className="text-muted-foreground">{value}%</span>          </div>          <Progress value={value} />        </div>      ))}    </div>  );}

A mesma barra por todo o range determinado - 0, 33, 66, e 100. Combine cada barra com seu valor numérico para que o preenchimento nunca seja silencioso: em 0 o usuário vê que a tarefa está na fila, em 100 que ela está pronta. value é limitado entre 0 e max (default 100).

Com label

Uploading invoice.pdf66%
<div className="flex flex-col gap-2">
  <div className="flex justify-between text-sm">
    <span>Uploading {file.name}</span>
    <span className="text-muted-foreground">{value}%</span>
  </div>
  <Progress value={value} />
</div>

A forma default para qualquer tarefa de longa duração com um total conhecido. Mantenha o texto do valor perto da barra para que os dois sejam lidos como um único widget.

Steps empilhados

{
  steps.map((step) => <Progress key={step.id} value={step.percent} />);
}

Para tarefas multi-stream (uploads paralelos, batch jobs reportando progresso por item). Combine cada row com um label por row fora da barra.

Barra fina dentro do header de um card

<Card>
  <CardHeader>
    <CardTitle>Sync</CardTitle>
    <Progress value={value} className="h-1" />
  </CardHeader>
  <CardContent>{content}</CardContent>
</Card>

Reduza a altura para h-1 quando a barra fica no topo de um card como uma lasca sutil de progresso em vez de uma superfície primária.

Acessibilidade

  • Role e valor: o Radix define role="progressbar", aria-valuemin="0", aria-valuemax="{max}", e aria-valuenow="{value}" automaticamente. Leitores de tela anunciam a porcentagem a cada mudança.
  • Label de valor: sobrescreva getValueLabel para anúncios localizados ou unidades não percentuais. O default é do estilo "{value}/{max}".
  • Nenhuma interação por teclado: Progress é não interativo. Se você precisa de um scrubber arrastável, recorra ao Slider.
  • Estado indeterminado: passe value={null} para remover aria-valuenow para que a tecnologia assistiva anuncie a tarefa como em progresso sem um número enganoso.
  • Movimento reduzido: o indicator usa transition-all para preenchimentos suaves. Usuários com prefers-reduced-motion: reduce recebem automaticamente o override global de movimento - nenhuma config extra necessária.

Relacionados

  • Skeleton - recorra ao Skeleton para fetches de duração desconhecida sem valor determinado.
  • Alert - primitive de feedback irmão para mensagens de contexto enquanto o progresso corre.
  • Slider - primitive irmão com um thumb arrastável quando o usuário controla o valor.

On this page