Step-by-Step Implementation of GenZ Carousel App

Step-by-Step Implementation

In this module, we will build the complete Gen-Z styled Image Carousel App from scratch using React + Vite. We'll walk through the project setup, structure, logic, animation with Framer Motion, and final styling using Tailwind CSS. You’ll follow along and build your own version just like the live app.

Set up the Environment

1) Install Node.js
First, make sure you have Node.js and npm installed. Download it from https://nodejs.org and verify:

node -v

npm -v

2) Create a React App with Vite

Open your terminal and run the following to scaffold a new React + Vite project:

npm create vite@latest genz-carousel-app -- --template react

Then:

cd genz-carousel-app

npm install

3) Start the App

Run the development server:

npm run dev

It will open at http://localhost:5173. You’ll see the default Vite + React template.

Install and Configure Tailwind CSS

We use Tailwind CSS for styling, and also Framer Motion for animations.

1) Install Tailwind CSS and PostCSS Plugins

Run:

npm install -D tailwindcss postcss autoprefixer

npx tailwindcss init -p

2) Configure Tailwind

In tailwind.config.js, update content:

export default {
  content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

3) Add Tailwind to CSS

In index.css, add:
@tailwind base;

@tailwind components;

@tailwind utilities;

4) Custom Font (Optional)

Add this in index.html inside <head>:
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">

And in body tag:

<body class="bg-black font-[Poppins]">

Create the Project Files

Your final folder structure will look like this:

genz-carousel-app/

├── public/

│   └── carousel/

│       ├── Helloooo.jpeg

│       ├── download.jpeg

│       └── CatQuote.jpeg

├── src/

│   ├── App.jsx

│   ├── Carousel.jsx

│   ├── index.css

│   └── main.jsx

├── index.html

├── tailwind.config.js

├── package.json

Let’s now build the components one by one.

Build the Carousel in App.jsx

Create a new file called App.jsx inside src/ and paste this:

import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import "./index.css";

const defaultImages = [
  "/carousel/Helloooo.jpeg",
  "/carousel/download.jpeg",
  "/carousel/CatQuote.jpeg",
];

function App() {
  const [uploadedImages, setUploadedImages] = useState([]);
  const [currentIndex, setCurrentIndex] = useState(0);

  const images = uploadedImages.length > 0 ? uploadedImages : defaultImages;

  const nextImage = () => {
    setCurrentIndex((prevIndex) => (prevIndex + 1) % images.length);
  };

  const prevImage = () => {
    setCurrentIndex((prevIndex) => (prevIndex - 1 + images.length) % images.length);
  };

  const handleUpload = (e) => {
    const files = Array.from(e.target.files).slice(0, 10);
    const urls = files.map((file) => URL.createObjectURL(file));
    setUploadedImages(urls);
    setCurrentIndex(0);
  };

  return (
    <div className="app-container">
      <h1 className="title">📸 Your Funtastic Gallery!</h1>

      <div style={{ marginBottom: "1.5rem" }}>
        <input
          type="file"
          multiple
          accept="image/*"
          onChange={handleUpload}
          style={{
            background: "#00eaff",
            border: "none",
            padding: "0.6rem 1.2rem",
            borderRadius: "1rem",
            color: "#000",
            fontWeight: "bold",
            cursor: "pointer"
          }}
        />
        <p style={{ fontSize: "0.9rem", color: "#00eaff", marginTop: "0.5rem" }}>
          Hello! Welcome to my carousel app! You can upload up to 10 images to create your own carousel and mini album!
        </p>
      </div>

      <div className="carousel">
        <button className="nav-button" onClick={prevImage}></button>

        <div className="image-container">
          <AnimatePresence mode="wait">
            <motion.img
              key={images[currentIndex]}
              src={images[currentIndex]}
              alt={`Slide ${currentIndex}`}
              initial={{ opacity: 0, x: 100 }}
              animate={{ opacity: 1, x: 0 }}
              exit={{ opacity: 0, x: -100 }}
              transition={{ duration: 0.6 }}
              className="carousel-image"
            />
          </AnimatePresence>
        </div>

        <button className="nav-button" onClick={nextImage}></button>
      </div>

      <div className="thumbnail-container">
        {images.map((img, index) => (
          <img
            key={index}
            src={img}
            alt={`Thumbnail ${index}`}
            onClick={() => setCurrentIndex(index)}
            className={`thumbnail ${index === currentIndex ? "active" : ""}`}
          />
        ))}
      </div>

      <p className="footer">
        Made by Jaishree Tomar for <a href="https://www.guvi.in/" target="_blank">GUVI</a>
      </p>
    </div>
  );
}

export default App;

Styling with index.css

In index.css, paste this styling to support all components and maintain the Gen-Z black+cyan theme:

body {
  margin: 0;
  font-family: "Segoe UI", sans-serif;
  background-color: #000;
  color: #fff;
  text-align: center;
  padding: 0 2rem 2rem;
}

.title {
  font-size: 2.2rem;
  margin: 0 0 1.5rem;
  color: #00eaff;
  font-weight: bold;
  letter-spacing: 0.5px;
}

.app-container {
  max-width: 800px;
  margin: 0 auto;
}

.carousel {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
}

.image-container {
  width: 700px;
  height: 450px;
  border-radius: 2rem;
  overflow: hidden;
  border: 4px solid #00eaff;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #111;
}

.carousel-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.nav-button {
  font-size: 2rem;
  background: transparent;
  border: none;
  color: #00eaff;
  cursor: pointer;
  transition: transform 0.2s ease;
}

.nav-button:hover {
  transform: scale(1.2);
}

.footer {
  margin-top: 2rem;
  font-size: 1rem;
  color: #aaa;
}

.footer a {
  color: #00eaff;
  text-decoration: none;
}

.footer a:hover {
  text-decoration: underline;
}

.thumbnail-container {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 1.5rem;
  gap: 0.7rem;
}

.thumbnail {
  width: 70px;
  height: 70px;
  border-radius: 0.5rem;
  object-fit: cover;
  cursor: pointer;
  opacity: 0.6;
  transition: all 0.3s ease;
  border: 2px solid transparent;
}

.thumbnail:hover {
  opacity: 1;
  transform: scale(1.05);
}

.thumbnail.active {
  border: 2px solid #00eaff;
  opacity: 1;
}

Setup Entry Point (main.jsx)

In main.jsx inside src/, replace the default code with:

import React from "react";

import ReactDOM from "react-dom/client";

import App from "./App.jsx";

import "./index.css";

ReactDOM.createRoot(document.getElementById("root")).render(

<React.StrictMode>

<App />

</React.StrictMode>

);

Add Default HTML and Font (index.html)

Update index.html inside the public/ folder like this:

Test and Run the App

Make sure your development server is running:

npm run dev

  1. Visit http://localhost:5173.
  2. Try uploading up to 10 images.
  3. Navigate between slides using arrows.
  4. Click thumbnails to jump to any image.

If everything works, congratulations — you’ve built your own animated, uploadable, modern image carousel app.