Ir al contenido
Contenido y datos

Progress

Cuánto falta para que termine algo. Determinada o indeterminada, en dos altos.

import { Progress } from "sebs7n-ui/progress"

Ejemplos

Una subida real

El `label` es el nombre accesible: no hace falta `aria-label`. `showValue` deja el porcentaje a la vista.

import { Button } from "sebs7n-ui/button"
import { Progress } from "sebs7n-ui/progress"
import { useEffect, useState } from "react"

function Subida() {
  // Arranca a mitad de camino: una barra vacía como primer cuadro de la página no muestra nada.
  const [valor, setValor] = useState(41)
  const [corriendo, setCorriendo] = useState(false)

  useEffect(() => {
    if (!corriendo) return
    const id = setInterval(() => {
      setValor((actual) => {
        const siguiente = Math.min(100, actual + 7)
        if (siguiente === 100) setCorriendo(false)
        return siguiente
      })
    }, 300)
    return () => clearInterval(id)
  }, [corriendo])

  return (
    <div className="flex w-full max-w-sm flex-col gap-4">
      <Progress label="facturas-2026.zip" showValue value={valor} />
      <div className="flex gap-2">
        <Button
          onClick={() => {
            setValor(0)
            setCorriendo(true)
          }}
          size="sm"
          variant="secondary"
        >
          Subir de nuevo
        </Button>
        <Button disabled={!corriendo} onClick={() => setCorriendo(false)} size="sm" variant="ghost">
          Pausar
        </Button>
      </div>
    </div>
  )
}

Determinada e indeterminada

Con `value={null}` no hay porcentaje: Base UI saca `aria-valuenow` y la barra pasa a ser una franja que recorre la pista. Es para cuando no se puede saber cuánto falta.

import { Progress } from "sebs7n-ui/progress"

function Indeterminada() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-6">
      <Progress label="Importando clientes" showValue value={68} />
      <Progress label="Consultando a AFIP" value={null} />
    </div>
  )
}

Tamaños y uso en una fila

`sm` (4px) dentro de una fila o una card chica; `md` (6px) suelto. Sin etiqueta visible va `aria-label`.

import { Progress } from "sebs7n-ui/progress"

function Tamanos() {
  const cuotas = [
    { plan: "Plan Pro", pagadas: 9 },
    { plan: "Plan Equipo", pagadas: 4 },
  ]
  return (
    <div className="flex w-full max-w-sm flex-col gap-4">
      {cuotas.map((cuota) => (
        <div className="flex flex-col gap-1.5" key={cuota.plan}>
          <div className="flex items-baseline justify-between">
            <span className="text-callout text-label">{cuota.plan}</span>
            <span className="text-callout text-label-secondary">{cuota.pagadas} de 12 cuotas</span>
          </div>
          <Progress
            aria-label={`Cuotas pagadas de ${cuota.plan}`}
            max={12}
            size="sm"
            value={cuota.pagadas}
          />
        </div>
      ))}
      <Progress aria-label="Espacio usado" size="md" value={100} />
    </div>
  )
}

Props

Generadas del TypeScript del paquete. Las propias del componente, más las heredadas del primitivo que tienen algo que explicar —marcadas «heredada de Base UI»—. El resto está en la línea «hereda de».

Progress

PropTipoPor defectoDescripción
value*number—Heredada de Base UI. El valor actual. null la deja indeterminada.
labelNonNullable<ReactNode>—El nombre visible de la barra. Es la forma preferida de nombrarla; sin él, el tipo exige aria-label o aria-labelledby.
showValuebooleanfalseMuestra el porcentaje a la derecha. Indeterminada no muestra número.
size"sm" | "md""md"sm 4px · md 6px de alto de la pista.
trackClassNamestring—Clases de la pista (el riel gris), por si hay que cambiarle el ancho o el radio.
classNamestring—Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana.

Teclado

—
No es interactivo.

Accesibilidad

  • Emite role="progressbar" con aria-valuenow, aria-valuemin y aria-valuemax.
  • Con value={null} es indeterminada: desaparece aria-valuenow y el lector anuncia que está en curso, sin porcentaje.
  • El nombre es obligatorio y lo exige el tipo: label (visible, la preferida), aria-label o aria-labelledby. Una barra sin nombre se anuncia «60 %» y nada más, y el 60 % de qué es justamente lo que hace falta saber.
  • Con movimiento reducido la franja indeterminada no queda congelada a mitad de camino: la pista se llena de un gris más apagado.

Reglas de uso

  • Si sabés cuánto falta, pasá el número. La indeterminada es para cuando no se puede saber.
  • La forma de algo que todavía no llegó es un Skeleton; el spinner de una acción es Button loading.
  • Poné label o aria-label: una barra sin nombre no dice qué está progresando.
  • size="sm" dentro de una fila o una card chica; md suelto.

Relacionados