A highly customizable React top-loading bar component with hook-based, ref-based, and state-based control patterns.
64
The state-based approach uses the controlled component pattern, where you manage the progress state in your component and pass it to the LoadingBar as a prop. This provides React-style declarative control over the loading bar.
Control the loading bar by managing progress state:
import React, { useState } from "react";
import LoadingBar from "react-top-loading-bar";
const App = () => {
const [progress, setProgress] = useState(0);
return (
<div>
<LoadingBar
color="#f11946"
progress={progress}
onLoaderFinished={() => setProgress(0)}
/>
<button onClick={() => setProgress(100)}>Complete</button>
</div>
);
};interface IProps {
// State Control
progress?: number;
onLoaderFinished?: () => void;
// Visual Properties
color?: string;
background?: string;
height?: number;
shadow?: boolean;
className?: string;
containerClassName?: string;
style?: CSSProperties;
containerStyle?: CSSProperties;
shadowStyle?: CSSProperties;
// Animation Timing
loaderSpeed?: number;
transitionTime?: number;
waitingTime?: number;
}/**
* Current progress value (0-100)
*/
progress?: number;
/**
* Callback fired when loading animation completes
* Called after the bar reaches 100% and fade animation finishes
*/
onLoaderFinished?: () => void;const SimpleProgress = () => {
const [progress, setProgress] = useState(0);
const handleStart = () => setProgress(20);
const handleIncrease = () => setProgress(prev => Math.min(prev + 20, 100));
const handleComplete = () => setProgress(100);
return (
<div>
<LoadingBar
color="blue"
progress={progress}
onLoaderFinished={() => setProgress(0)}
/>
<button onClick={handleStart}>Start (20%)</button>
<button onClick={handleIncrease}>+20%</button>
<button onClick={handleComplete}>Complete</button>
</div>
);
};const ApiExample = () => {
const [progress, setProgress] = useState(0);
const [loading, setLoading] = useState(false);
const fetchData = async () => {
setLoading(true);
setProgress(10);
try {
// Start request
setProgress(30);
const response = await fetch("/api/data");
// Processing
setProgress(70);
const data = await response.json();
// Complete
setProgress(100);
} catch (error) {
setProgress(100); // Complete on error too
} finally {
setLoading(false);
}
};
return (
<div>
<LoadingBar
color="green"
progress={progress}
onLoaderFinished={() => setProgress(0)}
/>
<button onClick={fetchData} disabled={loading}>
{loading ? "Loading..." : "Fetch Data"}
</button>
</div>
);
};const FormSubmission = () => {
const [progress, setProgress] = useState(0);
const [formData, setFormData] = useState({ name: "", email: "" });
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Validation
setProgress(20);
await new Promise(resolve => setTimeout(resolve, 300));
// Submit
setProgress(50);
await fetch("/api/submit", {
method: "POST",
body: JSON.stringify(formData),
});
// Processing
setProgress(80);
await new Promise(resolve => setTimeout(resolve, 500));
// Complete
setProgress(100);
};
return (
<div>
<LoadingBar
color="purple"
progress={progress}
onLoaderFinished={() => {
setProgress(0);
alert("Form submitted successfully!");
}}
/>
<form onSubmit={handleSubmit}>
<input
value={formData.name}
onChange={(e) => setFormData(prev => ({ ...prev, name: e.target.value }))}
placeholder="Name"
/>
<input
value={formData.email}
onChange={(e) => setFormData(prev => ({ ...prev, email: e.target.value }))}
placeholder="Email"
/>
<button type="submit">Submit</button>
</form>
</div>
);
};const MultiStepProcess = () => {
const [progress, setProgress] = useState(0);
const [currentStep, setCurrentStep] = useState(0);
const steps = [
{ name: "Initialize", progress: 10 },
{ name: "Validate", progress: 30 },
{ name: "Process", progress: 60 },
{ name: "Finalize", progress: 90 },
{ name: "Complete", progress: 100 },
];
const executeStep = async (stepIndex: number) => {
setCurrentStep(stepIndex);
setProgress(steps[stepIndex].progress);
// Simulate step execution
await new Promise(resolve => setTimeout(resolve, 1000));
if (stepIndex < steps.length - 1) {
executeStep(stepIndex + 1);
}
};
return (
<div>
<LoadingBar
color="orange"
progress={progress}
onLoaderFinished={() => {
setProgress(0);
setCurrentStep(0);
}}
/>
<p>Current Step: {steps[currentStep]?.name}</p>
<button onClick={() => executeStep(0)}>Start Process</button>
</div>
);
};const FileUpload = () => {
const [progress, setProgress] = useState(0);
const uploadFile = (file: File) => {
const formData = new FormData();
formData.append("file", file);
const xhr = new XMLHttpRequest();
// Track upload progress
xhr.upload.addEventListener("progress", (e) => {
if (e.lengthComputable) {
const percentComplete = (e.loaded / e.total) * 100;
setProgress(percentComplete);
}
});
xhr.onload = () => {
setProgress(100);
};
xhr.open("POST", "/upload");
xhr.send(formData);
};
return (
<div>
<LoadingBar
color="red"
progress={progress}
onLoaderFinished={() => setProgress(0)}
/>
<input
type="file"
onChange={(e) => e.target.files?.[0] && uploadFile(e.target.files[0])}
/>
</div>
);
};Customize appearance through props:
<LoadingBar
progress={progress}
color="#ff6b6b"
height={4}
shadow={true}
background="rgba(255,255,255,0.1)"
loaderSpeed={300}
transitionTime={200}
waitingTime={500}
className="custom-loader"
containerClassName="custom-container"
style={{ borderRadius: "2px" }}
onLoaderFinished={() => console.log("Done!")}
/>onLoaderFinished callback to reset progress to 0 after completionInstall with Tessl CLI
npx tessl i tessl/npm-react-top-loading-barevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10