Progress

Component

Refined Tailwind progress bar components and Tailwind CSS loading indicators displaying operation status with smooth animations.

Install via CLI

Run this command to automatically add the component and its dependencies to your project.

npx @abhaysinghr516/business-wish add progress
New to the CLI? Run npx @abhaysinghr516/business-wish init first to initialize your project.

Keeping users informed during long tasks is paramount to a premium experience. A sleek Tailwind progress bar provides immediate, clear feedback. This collection of Tailwind CSS loading indicators includes animated gradients, floating percentage labels, and beautiful circular SVGs.

Use a progress bar alongside a File Upload zone to indicate transfer status, or swap it out for an indeterminate Loader when you cannot calculate the exact duration.

Sleek Basic Progress

import React, { useState, useEffect } from "react";

const BasicProgress = () => {
  const [progress, setProgress] = useState(0);

  useEffect(() => {
    const timer = setTimeout(() => setProgress(65), 500);
    return () => clearTimeout(timer);
  }, []);

  return (
    <div className="w-full max-w-md mx-auto my-8">
      <div className="h-1.5 w-full bg-neutral-100 dark:bg-neutral-800 rounded-full overflow-hidden">
        <div
          className="h-full bg-neutral-900 dark:bg-white rounded-full transition-all duration-1000 ease-out"
          style={{ width: `${progress}%` }}
        />
      </div>
    </div>
  );
};

export default BasicProgress;

Progress with Floating Label

import React, { useState, useEffect } from "react";

const ProgressWithLabel = () => {
  const [progress, setProgress] = useState(0);

  useEffect(() => {
    const timer = setTimeout(() => setProgress(82), 500);
    return () => clearTimeout(timer);
  }, []);

  return (
    <div className="w-full max-w-md mx-auto my-8 mt-12">
      <div className="relative h-2 w-full bg-neutral-100 dark:bg-neutral-800 rounded-full">
        <div
          className="absolute top-0 left-0 h-full bg-blue-500 rounded-full transition-all duration-1000 ease-out"
          style={{ width: `${progress}%` }}
        >
          <div className="absolute -top-8 right-0 translate-x-1/2">
            <span className="bg-neutral-900 dark:bg-white text-white dark:text-neutral-900 text-[11px] font-bold px-2 py-1 rounded-md shadow-sm">
              {progress}%
            </span>
            <div className="w-2 h-2 bg-neutral-900 dark:bg-white rotate-45 absolute -bottom-1 left-1/2 -translate-x-1/2" />
          </div>
        </div>
      </div>
    </div>
  );
};

export default ProgressWithLabel;

Animated Gradient Progress

import React, { useState, useEffect } from "react";

const AnimatedProgress = () => {
  const [progress, setProgress] = useState(0);

  useEffect(() => {
    const timer = setTimeout(() => setProgress(100), 500);
    return () => clearTimeout(timer);
  }, []);

  return (
    <div className="w-full max-w-md mx-auto my-8">
      <div className="flex justify-between items-end mb-2">
        <span className="text-[13px] font-medium text-neutral-600 dark:text-neutral-400">Uploading files...</span>
        <span className="text-[13px] font-semibold text-neutral-900 dark:text-white">{progress}%</span>
      </div>
      <div className="h-2 w-full bg-neutral-100 dark:bg-neutral-800 rounded-full overflow-hidden relative">
        <div
          className="absolute top-0 left-0 h-full rounded-full transition-all duration-1000 ease-out bg-gradient-to-r from-blue-500 via-indigo-500 to-purple-500"
          style={{ width: `${progress}%` }}
        >
          {/* Animated shimmer overlay */}
          <div className="absolute inset-0 w-full h-full bg-gradient-to-r from-transparent via-white/30 to-transparent -translate-x-full animate-[shimmer_2s_infinite]" />
        </div>
      </div>
      <style>{`
        @keyframes shimmer {
          100% { transform: translateX(100%); }
        }
      `}</style>
    </div>
  );
};

export default AnimatedProgress;

Circular Progress Indicator

import React, { useState, useEffect } from "react";

const CircularProgress = () => {
  const [progress, setProgress] = useState(0);
  const size = 120;
  const strokeWidth = 8;
  const radius = (size - strokeWidth) / 2;
  const circumference = radius * 2 * Math.PI;
  const offset = circumference - (progress / 100) * circumference;

  useEffect(() => {
    const timer = setTimeout(() => setProgress(75), 500);
    return () => clearTimeout(timer);
  }, []);

  return (
    <div className="flex items-center justify-center my-8">
      <div className="relative" style={{ width: size, height: size }}>
        {/* Background Circle */}
        <svg className="w-full h-full -rotate-90" viewBox={`0 0 ${size} ${size}`}>
          <circle
            className="text-neutral-100 dark:text-neutral-800"
            strokeWidth={strokeWidth}
            stroke="currentColor"
            fill="transparent"
            r={radius}
            cx={size / 2}
            cy={size / 2}
          />
          {/* Progress Circle */}
          <circle
            className="text-neutral-900 dark:text-white transition-all duration-1000 ease-out"
            strokeWidth={strokeWidth}
            strokeDasharray={circumference}
            strokeDashoffset={offset}
            strokeLinecap="round"
            stroke="currentColor"
            fill="transparent"
            r={radius}
            cx={size / 2}
            cy={size / 2}
          />
        </svg>
        {/* Center Text */}
        <div className="absolute inset-0 flex flex-col items-center justify-center">
          <span className="text-3xl font-semibold text-neutral-900 dark:text-white tracking-tighter">
            {progress}<span className="text-lg text-neutral-400">%</span>
          </span>
        </div>
      </div>
    </div>
  );
};

export default CircularProgress;

Segments Progress

import React, { useState, useEffect } from "react";

const SegmentsProgress = () => {
  const [currentStep, setCurrentStep] = useState(0);
  const totalSteps = 4;

  useEffect(() => {
    const timer = setTimeout(() => setCurrentStep(2), 500);
    return () => clearTimeout(timer);
  }, []);

  return (
    <div className="w-full max-w-md mx-auto my-8">
      <div className="flex justify-between items-end mb-3">
        <span className="text-[13px] font-medium text-neutral-600 dark:text-neutral-400">Account Setup</span>
        <span className="text-[13px] font-semibold text-neutral-900 dark:text-white">Step {currentStep + 1} of {totalSteps}</span>
      </div>
      <div className="flex items-center justify-between gap-2">
        {[...Array(totalSteps)].map((_, i) => (
          <div key={i} className="h-1.5 w-full bg-neutral-100 dark:bg-neutral-800 rounded-full overflow-hidden">
            <div
              className={`h-full rounded-full transition-all duration-500 ease-out ${
                i <= currentStep ? "bg-neutral-900 dark:bg-white w-full" : "w-0"
              }`}
            />
          </div>
        ))}
      </div>
    </div>
  );
};

export default SegmentsProgress;

Indeterminate Progress

import React from "react";

const IndeterminateProgress = () => {
  return (
    <div className="w-full max-w-md mx-auto my-8">
      <div className="h-1 w-full bg-neutral-100 dark:bg-neutral-800 overflow-hidden relative rounded-full">
        <div className="absolute top-0 h-full bg-neutral-900 dark:bg-white w-1/3 rounded-full animate-[indeterminate_1.5s_infinite_ease-in-out]" />
      </div>
      <style>{`
        @keyframes indeterminate {
          0% { left: -35%; right: 100%; }
          60% { left: 100%; right: -90%; }
          100% { left: 100%; right: -90%; }
        }
      `}</style>
    </div>
  );
};

export default IndeterminateProgress;