Display

ProgressBar

Indicador de progreso lineal

Preview

size
value
animated

Code

import css from "./ProgressBar.module.css";

type Size = "xs" | "sm" | "md" | "lg";

interface ResponsiveSize {
  base: Size;
  mobile?: Size;
  tablet?: Size;
  desktop?: Size;
  wide?: Size;
}

interface ProgressBarProps {
  size: Size | ResponsiveSize;
  value: number;
  // Named after the attribute it becomes: the bar draws no text of its own.
  "aria-label": string;
  animated?: boolean;
}

function getSizeClasses(size: Size | ResponsiveSize): string {
  if (typeof size === "string") {
    return css[size];
  }

  const classes = [css[`${size.base}_base`]];

  if (size.mobile) classes.push(css[`${size.mobile}_mobile`]);
  if (size.tablet) classes.push(css[`${size.tablet}_tablet`]);
  if (size.desktop) classes.push(css[`${size.desktop}_desktop`]);
  if (size.wide) classes.push(css[`${size.wide}_wide`]);

  return classes.join(" ");
}

export default function ProgressBar({
  size,
  value,
  "aria-label": ariaLabel,
  animated,
}: ProgressBarProps) {
  return (
    <div
      className={`
        ${css.progressbar}
        ${getSizeClasses(size)}
      `}
      role="progressbar"
      aria-label={ariaLabel}
      aria-valuenow={value}
      aria-valuemin={0}
      aria-valuemax={100}
    >
      <div
        className={`${css.progressbar_fill} ${animated ? css.animated : ""}`}
        style={
          animated
            ? ({ "--progress-value": `${value}%` } as React.CSSProperties)
            : { width: `${value}%` }
        }
      ></div>
    </div>
  );
}

Props

PropTypeRequiredDescription
size"xs" | "sm" | "md" | "lg" | ResponsiveSizerequiredGrosor de la barra. Fijo o responsive.
valuenumberrequiredProgreso en porcentaje (0–100).
aria-labelstringrequiredNombre de la barra para lectores de pantalla; la barra no dibuja texto.
animatedboolean—Anima el llenado y cada cambio de valor.