Back to Code Bytes
3 min read
React Progress Bar

Description

The ProgressBar component is a customizable and animated React component that visually represents progress as a horizontal bar. It allows you to display a percentage of completion ranging from 0% to 100%, making it ideal for indicating loading states, upload progress, or any measurable task completion.

🏎️ Example

Default Progress Bar

With Border Style Square

Change the border style to square or rounded by passing either Square or Rounded to borderStyle.


🦾 Usage

import { ProgressBar } from './ProgressBar';

function App() {
  return (
    <div>
      <h1>File Upload Progress</h1>
      <ProgressBar percent={75} color="#4caf50" borderStyle="Rounded" thickness="10" />
    </div>
  );
}

🍎 Code Byte

ProgressBar.tsx

import React from "react";
import clsx from "clsx";
import { motion } from "framer-motion";
import round from "lodash-es/round";
import styles from "./ProgressBar.module.css";

export const borderStyles = ["Square", "Rounded"] as const;
export type BorderStyle = (typeof borderStyles)[number];

const getBarValueStyles = (
  backgroundColor: string,
  value: number,
  thickness: string,
) => {
  return {
    backgroundColor: backgroundColor,
    width: `${value}%`,
    height: `${thickness}px`,
  };
};

export interface ProgressBarProps {
  percent: number;
  borderStyle?: BorderStyle;
  color?: string;
  thickness?: string;
  className?: string;
  ariaLabel?: string;
}

export const ProgressBar = ({
  className = "",
  color = "#16a34a",
  borderStyle = "Rounded",
  percent,
  thickness = "7",
  ariaLabel = "Progress Bar",
}: ProgressBarProps) => {
  const value = percent > 100 ? 100 : percent;

  const barValueStyles = {
    ...getBarValueStyles(color, value, thickness),
  };

  const borderRadius = clsx({
    [styles.rounderBorderRadius as string]: borderStyle === "Rounded",
    [styles.squareBorderRadius as string]: borderStyle === "Square",
  });

  return (
    <div
      aria-valuemax={100}
      aria-valuemin={0}
      aria-valuenow={round(value, 2)}
      aria-valuetext={`${round(value, 2)}% complete`}
      className={clsx(
        styles.progressBar,
        styles.progressGauge,
        borderRadius,
        className,
      )}
      role="progressbar"
      aria-label={ariaLabel}
    >
      <motion.div
        className={clsx(styles.progressBar, styles.barValue, borderRadius)}
        initial={{ width: 0 }}
        animate={{ width: barValueStyles.width }}
        transition={{
          type: "tween",
          duration: 1,
          ease: "easeInOut",
        }}
        style={barValueStyles}
      />
    </div>
  );
};

export default ProgressBar;

ProgressBar.module.css

.progressBar {
  &.progressGauge {
    background-color: #e0e0de;
    display: inline-flex;
    flex-direction: row;
    justify-content: flex-start;
    width: 100%;
  }

  .barValue {
    display: inline-block;
  }

  .squareBorderRadius,
  &.squareBorderRadius {
    border-radius: 0;
  }

  .rounderBorderRadius,
  &.rounderBorderRadius {
    border-radius: 16px;
  }
}

🪑 Props

PropTypeDescription
percentnumberThe percentage of completion of the progress bar, ranging from 0 - 100.
borderStylestringRounded or Square
colorstringThe color applied to the progress portion of the bar.
thicknessstringThe thickness of the progress bar.
classNamestringApply your own styles with className.