Retour au catalogue

Loading Progress Bar

Barre de progression avec etapes textuelles, spinner et pourcentage.

loading-statessimple Both Responsive a11y
minimalsaasuniversalcentered
Theme
"use client";

import { useState, useEffect } from "react";
import { motion } from "framer-motion";

interface LoadingProgressBarProps {
  label?: string;
  steps?: string[];
  duration?: number;
}

export default function LoadingProgressBar({
  label = "Chargement...",
  steps = [],
  duration = 3000,
}: LoadingProgressBarProps) {
  const [progress, setProgress] = useState(0);
  const [stepIndex, setStepIndex] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setProgress((prev) => {
        const next = prev + 2;
        if (next >= 100) { clearInterval(interval); return 100; }
        return next;
      });
    }, duration / 50);
    return () => clearInterval(interval);
  }, [duration]);

  useEffect(() => {
    if (steps.length === 0) return;
    const stepSize = 100 / steps.length;
    setStepIndex(Math.min(Math.floor(progress / stepSize), steps.length - 1));
  }, [progress, steps]);

  return (
    <div className="py-20 px-6" style={{ background: "var(--color-background)" }}>
      <div className="mx-auto max-w-sm text-center">
        <div className="mb-4">
          <motion.div
            animate={{ rotate: 360 }}
            transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
            className="inline-block w-8 h-8 rounded-full"
            style={{ border: "2px solid var(--color-border)", borderTopColor: "var(--color-accent)" }}
          />
        </div>

        <h3 className="text-sm font-semibold mb-1" style={{ color: "var(--color-foreground)" }}>{label}</h3>
        {steps.length > 0 && (
          <p className="text-xs mb-4" style={{ color: "var(--color-foreground-muted)" }}>{steps[stepIndex]}</p>
        )}

        <div className="h-2 rounded-full overflow-hidden mb-2" style={{ background: "var(--color-background-alt)" }}>
          <motion.div className="h-full rounded-full" style={{ background: "var(--color-accent)" }} animate={{ width: `${progress}%` }} transition={{ duration: 0.1 }} />
        </div>

        <span className="text-xs font-medium" style={{ color: "var(--color-foreground-light)" }}>{progress}%</span>
      </div>
    </div>
  );
}

Avis

Loading Progress Bar — React Loading-states Section — Incubator