DEV Community

Cover image for Building a Dynamic Carousel Component with Shadcn UI, ViteJS, TailwindCSS, and ReactJS (with TypeScript)
Santiago Moraga Caldera
Santiago Moraga Caldera

Posted on

Building a Dynamic Carousel Component with Shadcn UI, ViteJS, TailwindCSS, and ReactJS (with TypeScript)

Github Repository

Carousels are an essential part of modern web applications, enabling you to display content like images, promotions, or testimonials in an interactive and visually appealing manner. In this tutorial, we’ll walk you through creating a dynamic carousel component using Shadcn UI, ViteJS, TailwindCSS, and ReactJS with TypeScript. By the end, you’ll have a fully functional and reusable carousel for your projects.

Introduction

Carousels make content engaging and easy to consume, offering users a better browsing experience. This guide covers the setup, implementation, and explanation of a carousel component using Shadcn UI, React, and supporting libraries. We’ll use:

  • Shadcn UI for pre-built components and utilities.
  • ViteJS for a fast and modern development environment.
  • TailwindCSS for styling.
  • ReactJS with TypeScript for dynamic functionality and type safety.

This tutorial ensures you not only learn the "how" but also understand the "why" of each piece of functionality.

Setting Up the Project

To follow along, ensure you have Node.js and npm or Yarn installed on your system.

1.Initialize the Project

Run the following commands to set up a Vite project with React and TypeScript:

npm create vite@latest
cd my-carousel
npm install
Enter fullscreen mode Exit fullscreen mode

2.Install Dependencies

Add the required packages for this project:

npm install embla-carousel-react embla-carousel-autoplay
Enter fullscreen mode Exit fullscreen mode
npm install -D tailwindcss postcss autoprefixer
Enter fullscreen mode Exit fullscreen mode
npx shadcn@latest init
Enter fullscreen mode Exit fullscreen mode

3.Set Up TailwindCSS

TailwindCSS DOCs

4.Set Up ShadcnUI

ShadcnUI DOCs

Import the pre-built Shadcn UI components into your project. For this example, we’ll use the Carousel and Button components.

5.Create a Carousel Component

Add the CustomCarousel component in src/custom-carousel.tsx.

The Custom Carousel Code

Here is the complete implementation of the carousel component:

import {
  Carousel,
  CarouselApi,
  CarouselContent,
  CarouselItem,
} from "@/components/ui/carousel";
import Autoplay from "embla-carousel-autoplay";
import { useCallback, useEffect, useState } from "react";
import { Button } from "./components/ui/button";

export const CustomCarousel = () => {
  const [carouselAPI, setCarouselAPI] = useState<CarouselApi | null>(null);
  const [selectedIndex, setSelectedIndex] = useState(0);
  const [scrollSnaps, setScrollSnaps] = useState<number[]>([]);

  const onSelect = useCallback(() => {
    if (!carouselAPI) return;

    setSelectedIndex(carouselAPI.selectedScrollSnap());
  }, [carouselAPI]);

  const scrollTo = (index: number) => {
    if (!carouselAPI) return;

    carouselAPI.scrollTo(index);
  };

  useEffect(() => {
    if (!carouselAPI) return;

    onSelect();

    setScrollSnaps(carouselAPI.scrollSnapList());

    carouselAPI.on("select", onSelect);
  }, [carouselAPI, onSelect]);

  return (
    <div>
      <Carousel
        plugins={[Autoplay({ delay: 2500 })]}
        opts={{ loop: true, align: "center" }}
        setApi={setCarouselAPI}
      >
        <CarouselContent>
          {[...Array(6)].map((_, index) => (
            <CarouselItem key={index} className="md:basis-1/2">
              <div className="border rounded-md h-[16rem] bg-muted/50 flex items-center justify-center md:h-[20rem]">
                <p className="font-bold text-2xl text-muted-foreground">
                  {index + 1}
                </p>
              </div>
            </CarouselItem>
          ))}
        </CarouselContent>
      </Carousel>
      <div className="flex justify-center mt-4 space-x-2">
        {scrollSnaps.map((_, index) => (
          <Button
            key={index}
            onClick={() => scrollTo(index)}
            size="icon"
            className={`w-2 h-2 rounded-full ${
              selectedIndex === index ? "bg-primary" : "bg-gray-300"
            }`}
          />
        ))}
      </div>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Explanation of the Code

1.State Management

carouselAPI: Stores the API object returned by the carousel, giving access to methods like scrollTo and selectedScrollSnap.

selectedIndex: Tracks the currently selected slide index.

scrollSnaps: Stores an array of snap points, representing the indices of the slides.

2.Event Handling

onSelect: Updates the selectedIndex whenever the user selects a new slide. It ensures the UI stays in sync with the carousel's state.

scrollTo: Allows programmatic navigation to a specific slide based on its index. This enables interaction through buttons or other controls.

3.Lifecycle Management

The useEffect hook ensures the carousel initializes correctly:

  • Calls onSelect to sync the selectedIndex state initially.
  • Sets up scrollSnaps using the carouselAPI.scrollSnapList method.
  • Attaches an event listener to keep selectedIndex updated.

Final Result

The carousel is now fully functional with the following features:

  • Autoplay with a configurable delay.
  • Looping for seamless content browsing.
  • Navigation dots that update dynamically based on the current slide.
  • Responsive design with TailwindCSS.

Conclusion

Congratulations! You've successfully built a reusable carousel component using Shadcn UI, ViteJS, TailwindCSS, and ReactJS with TypeScript. This powerful combination ensures your component is both visually appealing and highly functional.

Feel free to customize the styles, add new features, or integrate this carousel into your projects. Let me know how it worked for you in the comments!

Top comments (0)