Docs
Carousel

Carousel

These components are used to build the carousel of the website.

Installation

First, you need to first install the embla-carousel package to get started.

npm install embla-carousel-react embla-carousel-autoplay --save

Then copy paste the carousel button and indicator code into your project.

carousel-button.tsx
"use client";
 
import React, {
  ComponentPropsWithRef,
  useCallback,
  useEffect,
  useState,
} from "react";
import { EmblaCarouselType } from "embla-carousel";
 
type UseCarouselButtonsType = {
  prevBtnDisabled: boolean;
  nextBtnDisabled: boolean;
  onPrevButtonClick: () => void;
  onNextButtonClick: () => void;
};
 
export const useCarouselButtons = (
  emblaApi: EmblaCarouselType | undefined,
  onButtonClick?: (emblaApi: EmblaCarouselType) => void,
): UseCarouselButtonsType => {
  const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);
  const [nextBtnDisabled, setNextBtnDisabled] = useState(true);
 
  const onPrevButtonClick = useCallback(() => {
    if (!emblaApi) return;
    emblaApi.scrollPrev();
    if (onButtonClick) onButtonClick(emblaApi);
  }, [emblaApi, onButtonClick]);
 
  const onNextButtonClick = useCallback(() => {
    if (!emblaApi) return;
    emblaApi.scrollNext();
    if (onButtonClick) onButtonClick(emblaApi);
  }, [emblaApi, onButtonClick]);
 
  const onSelect = useCallback((emblaApi: EmblaCarouselType) => {
    setPrevBtnDisabled(!emblaApi.canScrollPrev());
    setNextBtnDisabled(!emblaApi.canScrollNext());
  }, []);
 
  useEffect(() => {
    if (!emblaApi) return;
 
    onSelect(emblaApi);
    emblaApi.on("reInit", onSelect).on("select", onSelect);
  }, [emblaApi, onSelect]);
 
  return {
    prevBtnDisabled,
    nextBtnDisabled,
    onPrevButtonClick,
    onNextButtonClick,
  };
};
 
type PropType = ComponentPropsWithRef<"button">;
 
export const PrevButton: React.FC<PropType> = (props) => {
  const { children, ...restProps } = props;
 
  return (
    <button type="button" {...restProps}>
      <svg className="w-[30%] h-[30%]" viewBox="0 0 532 532">
        <path
          fill="currentColor"
          d="M355.66 11.354c13.793-13.805 36.208-13.805 50.001 0 13.785 13.804 13.785 36.238 0 50.034L201.22 266l204.442 204.61c13.785 13.805 13.785 36.239 0 50.044-13.793 13.796-36.208 13.796-50.002 0a5994246.277 5994246.277 0 0 0-229.332-229.454 35.065 35.065 0 0 1-10.326-25.126c0-9.2 3.393-18.26 10.326-25.2C172.192 194.973 332.731 34.31 355.66 11.354Z"
        />
      </svg>
      {children}
    </button>
  );
};
 
export const NextButton: React.FC<PropType> = (props) => {
  const { children, ...restProps } = props;
 
  return (
    <button type="button" {...restProps}>
      <svg className="w-[30%] h-[30%]" viewBox="0 0 532 532">
        <path
          fill="currentColor"
          d="M176.34 520.646c-13.793 13.805-36.208 13.805-50.001 0-13.785-13.804-13.785-36.238 0-50.034L330.78 266 126.34 61.391c-13.785-13.805-13.785-36.239 0-50.044 13.793-13.796 36.208-13.796 50.002 0 22.928 22.947 206.395 206.507 229.332 229.454a35.065 35.065 0 0 1 10.326 25.126c0 9.2-3.393 18.26-10.326 25.2-45.865 45.901-206.404 206.564-229.332 229.52Z"
        />
      </svg>
      {children}
    </button>
  );
};
carousel-indicator.tsx
"use client";
 
import React, {
  ComponentPropsWithRef,
  useCallback,
  useEffect,
  useState,
} from "react";
import { EmblaCarouselType } from "embla-carousel";
 
type useCarouselIndicatorType = {
  selectedIndex: number;
  scrollSnaps: number[];
  onDotButtonClick: (index: number) => void;
};
 
export const useCarouselIndicator = (
  emblaApi: EmblaCarouselType | undefined,
): useCarouselIndicatorType => {
  const [selectedIndex, setSelectedIndex] = useState(0);
  const [scrollSnaps, setScrollSnaps] = useState<number[]>([]);
 
  const onDotButtonClick = useCallback(
    (index: number) => {
      if (!emblaApi) return;
      emblaApi.scrollTo(index);
    },
    [emblaApi],
  );
 
  const onInit = useCallback((emblaApi: EmblaCarouselType) => {
    setScrollSnaps(emblaApi.scrollSnapList());
  }, []);
 
  const onSelect = useCallback((emblaApi: EmblaCarouselType) => {
    setSelectedIndex(emblaApi.selectedScrollSnap());
  }, []);
 
  useEffect(() => {
    if (!emblaApi) return;
 
    onInit(emblaApi);
    onSelect(emblaApi);
    emblaApi.on("reInit", onInit).on("reInit", onSelect).on("select", onSelect);
  }, [emblaApi, onInit, onSelect]);
 
  return {
    selectedIndex,
    scrollSnaps,
    onDotButtonClick,
  };
};
 
type PropType = ComponentPropsWithRef<"button">;
 
export const CarouselIndicator: React.FC<PropType> = (props) => {
  const { children, ...restProps } = props;
 
  return (
    <button type="button" {...restProps}>
      {children}
    </button>
  );
};

Props

PropTypeDescriptionDefault
classNamestringThe class name to be applied to the carousel
slidesReact.ReactNode[]The array of slides to display in the carousel
optionsEmblaOptionsTypeConfiguration options for the carousel
maxRotateXnumberMaximum rotation on the X-axis45
maxRotateYnumberMaximum rotation on the Y-axis15
maxScalenumberMaximum scale factor0.9
tweenFactorBasenumberBase factor for tweening effects0.7
autoplaybooleanEnable autoplay functionalitytrue
autoplayDelaynumberDelay between autoplay transitions2000
showIndicatorsbooleanShow indicators for the slidestrue
showArrowsbooleanShow navigation arrowstrue