Creating a Loading Page with React and Tailwind CSS
In modern web development, delivering a seamless user experience is paramount. Visual feedback during loading intervals plays a pivotal role in maintaining user engagement and satisfaction. Loading pages serve not only to inform users about ongoing processes but also to keep them engaged while awaiting content. In this tutorial, we’ll delve into crafting an aesthetically pleasing loading page using Tailwind CSS and React, enriched with captivating animations to elevate the overall user experience.
Prerequisites
Before we get started, ensure you have the following:
- Basic understanding of React.
- Node.js and npm installed on your machine.
- A React project set up.
- Tailwind dependencies installed
- Framer Motion installed npm install framer-motion
This medium article provides a quick way to set up React and Tailwind.
Once the environment is set up, we can proceed.
App.jsx
import Page1 from "./components/Page1.jsx";
import LoaderSimple from "./components/LoaderSimple.jsx";
export default function App() {
return (
<>
<LoaderSimple />
<Page1 />
</>
);
}
Implementing a Loading Page
Step 1: Create a simple webpage
Page1.jsx
const background = "bg-blue";
function Page1(props) {
return (
<div className={`relative min-h-screen flex bg-black`}>
<div className="container max-w-screen-xl mx-auto flex justify-center items-center text-4xl text-white">
Page 1
</div>
</div>
);
}
export default Page1;
Step 2: Create a loading page
LoaderSimple.jsx
import { motion } from 'framer-motion';
function LoaderSimple(props) {
return (
<div className="fixed bg-black h-screen top-0 left-0 w-full h-full flex justify-center items-center z-10">
<div className="p-4 rounded-md">
<div className="flex justify-center">
<>
<motion.span
className="w-4 h-4 my-12 mx-1 bg-white rounded-full"
animate={{
y: [0, -20, 0],
opacity: [1, 0], // Fades out
transition: { duration: 1, repeat: Infinity }
}}
/>
<motion.span
className="w-4 h-4 my-12 mx-1 bg-white rounded-full"
animate={{
y: [0, -20, 0],
opacity: [1, 0], // Fades out
transition: { duration: 1, repeat: Infinity, delay: 0.2 }
}}
/>
<motion.span
className="w-4 h-4 my-12 mx-1 bg-white rounded-full"
animate={{
y: [0, -20, 0],
opacity: [1, 0], // Fades out
transition: { duration: 1, repeat: Infinity, delay: 0.4 }
}}
/>
</>
</div>
</div>
</div>
);
}
export default LoaderSimple;
Explanation:
- Packages
import { motion } from 'framer-motion';
: Imports the motion
component from the Framer Motion library for creating animations.
2. Animation Configuration:
- Each dot is animated using the
animate
prop provided by Framer Motion. - The animation specifies a vertical movement (
y
) from 0 to -20 and back to 0, simulating the dot's bouncing effect. - Additionally, the opacity of each dot gradually decreases from 1 to 0, creating a fading effect as the dot moves up.
3. Animation Duration and Repetition:
- The animation duration is set to 1 second (
transition: { duration: 1 }
). - The animation repeats infinitely (
repeat: Infinity
) to create an ongoing looping effect. - The delay between each dot’s animation is staggered using the
delay
property to create a sequential effect.
Step 3: Merging the Two Components Together
To seamlessly transition from the loading page to the main webpage, I implemented a fade-out effect on the loading page and a fade-in effect on the main webpage.
Update your LoaderSimple.jsx
import React, { useEffect, useState } from 'react';
import { motion, useAnimation } from 'framer-motion'; // Import useAnimation hook
function LoaderSimple(props) {
const [loading, setLoading] = useState(true);
const controls = useAnimation(); // Use useAnimation hook
useEffect(() => {
const timer = setTimeout(() => {
setLoading(false);
}, 4000);
return () => clearTimeout(timer);
}, []);
useEffect(() => {
if (loading) {
controls.start({
opacity: 1,
transition: { duration: 1 }
});
} else {
controls.start({
opacity: 0,
transition: { duration: 1 }
});
}
}, [loading, controls]);
return (
<motion.div
className="fixed bg-black h-screen top-0 left-0 w-full h-full flex justify-center items-center z-10"
animate={controls}
>
<div className="p-4 rounded-md">
<div className="flex justify-center">
<>
<motion.span
className="w-4 h-4 my-12 mx-1 bg-white rounded-full"
animate={{
y: [0, -20, 0],
opacity: [1, 0], // Fades out
transition: { duration: 1, repeat: 2 }
}}
/>
<motion.span
className="w-4 h-4 my-12 mx-1 bg-white rounded-full"
animate={{
y: [0, -20, 0],
opacity: [1, 0], // Fades out
transition: { duration: 1, repeat: 1.8, delay: 0.2 }
}}
/>
<motion.span
className="w-4 h-4 my-12 mx-1 bg-white rounded-full"
animate={{
y: [0, -20, 0],
opacity: [1, 0], // Fades out
transition: { duration: 1, repeat: 1.6, delay: 0.4 }
}}
/>
</>
</div>
</div>
</motion.div>
);
}
export default LoaderSimple;
Explanation:
- useState Hook: The component uses the
useState
hook to manage the state of the loading animation. Initially, theloading
state is set totrue
, indicating that the loading animation should be displayed. - useEffect Hook (Timer): Another
useEffect
hook is used to set a timer that changes theloading
state tofalse
after 4000 milliseconds (4 seconds). This simulates a loading period before the content is ready to be displayed. - useEffect Hook (Controls): This
useEffect
hook controls the animation of the loading spinner. It starts the animation when the component mounts (loading
istrue
) and fades out the loading spinner when the content is ready (loading
isfalse
). It utilizes theuseAnimation
hook from Framer Motion to control the animation.
And voilà! You’ve successfully created a loading page using React and Tailwind CSS.