Progress

Component

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

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;