0

I am working on a project with a setup combination of react, tailwind and react icons. In my project multiple sliders are required (some has navigation, some has pagination etc…)

So, I created a slider factory component Carousel and controlling variation through props

// Carousel/index.jsx

import { Children, useState } from "react";
import { v4 as uuidv4 } from "uuid";
import { HiOutlineArrowLeft, HiOutlineArrowRight } from "react-icons/hi";
import { Swiper, SwiperSlide } from "swiper/react";
import { Autoplay, Keyboard, Mousewheel, Navigation, Pagination } from "swiper";
import "swiper/css";
import "swiper/css/pagination";
import "swiper/css/navigation";
import NextSlideBtn from "./NextSlideBtn";
import PrevSlideBtn from "./PrevSlideBtn";

const Carousel = ({
    children,
    loop,
    pagination,
    navigation,
    autoplay,
    breakpoints,
}) => {
    const childrenArray = Children.toArray(children);

    const [swiperRef, setSwiperRef] = useState();

    return (
        <div className="group relative">
            <Swiper
                className="rounded overflow-hidden"
                onSwiper={setSwiperRef}
                modules={[
                    Autoplay,
                    Keyboard,
                    Mousewheel,
                    Pagination,
                    Navigation,
                ]}
                mousewheel
                keyboard
                grabCursor
                loop={loop || false}
                autoplay={
                    autoplay && {
                        delay: 5000,
                        disableOnInteraction: true,
                    }
                }
                spaceBetween={breakpoints && 20}
                breakpoints={
                    breakpoints && {
                        450: {
                            slidesPerView: 2,
                        },
                        768: {
                            slidesPerView: 3,
                        },
                        1536: {
                            slidesPerView: 4,
                        },
                    }
                }
                pagination={
                    pagination && {
                        clickable: true,
                    }
                }
            >
                {childrenArray.map((item) => (
                    <SwiperSlide key={uuidv4()}>{item}</SwiperSlide>
                ))}
            </Swiper>
            {navigation && (
                <div className="hidden group-hover:block">
                    <PrevSlideBtn swiperRef={swiperRef}>
                        <HiOutlineArrowLeft className="text-violet-600" />
                    </PrevSlideBtn>
                    <NextSlideBtn swiperRef={swiperRef}>
                        <HiOutlineArrowRight className="text-violet-600" />
                    </NextSlideBtn>
                </div>
            )}
        </div>
    );
};

export default Carousel;
// Carousel/NextSlideBtn.jsx

const NextSlideBtn = ({ children, swiperRef }) => {
    const handleNextSlide = () => swiperRef.slideNext();

    return (
        <button
            onClick={handleNextSlide}
            className="absolute z-50 top-1/2 -translate-y-1/2 -right-2 translate-x-2 bg-white shadow-md rounded-full p-3"
        >
            {children}
        </button>
    );
};

export default NextSlideBtn;
// Carousel/PrevSlideBtn.jsx

const PrevSlideBtn = ({ children, swiperRef }) => {
    const handlePrevSlide = () => swiperRef.slidePrev();

    return (
        <button
            onClick={handlePrevSlide}
            className="absolute z-50 top-1/2 -translate-y-1/2 -left-2 -translate-x-2 bg-white shadow-md rounded-full p-3"
        >
            {children}
        </button>
    );
};

export default PrevSlideBtn;

One of the requirement was to create custom navigation button, which I managed to accomplish as you can see in the code above, but for more visibility I am marking the flow in short

// Carousel/index.jsx

const [swiperRef, setSwiperRef] = useState();

<div>
    <Swiper
        onSwiper={setSwiperRef}
        ...
    >
    ...
    </Swiper>
    
    <PrevSlideBtn swiperRef={swiperRef} />
    <NextSlideBtn swiperRef={swiperRef} />
</div>

// Carousel/NextSlideBtn.jsx

const NextSlideBtn = ({ children, swiperRef }) => {
    const handleNextSlide = () => swiperRef.slideNext();

    return (
        <button
            onClick={handleNextSlide}
            ...
        >
            {children}
        </button>
    );
};

export default NextSlideBtn;

// Carousel/PrevSlideBtn.jsx

const PrevSlideBtn = ({ children, swiperRef }) => {
    const handlePrevSlide = () => swiperRef.slidePrev();

    return (
        <button
            onClick={handlePrevSlide}
            ...
        >
            {children}
        </button>
    );
};

export default PrevSlideBtn;

Couple of github issues, stackoverflow questions and swiper docs helped me out to accomplish this, and it was pretty straight forward to understand.

Now my question is how can I customize swiper react pagination (like radio buttons which some websites use, or any other styles…) using tailwind and I want to make it as a separate component like I did for navigation buttons.

I’ve tried many solutions eg:

const paginationBullets = {
        type: "custom",
        clickable: true,
        renderCustom: (_, current, total) => {
            return <MyCustomSwiperPaginationComponent current={current} total={total} />;
        },
    };

But nothing seems to work as expected.

Please help me out.

Component separation is my goal.

mSaif
  • 33
  • 4

0 Answers0