Search code examples
swiper.jsreact-swiper

React Swiper custom pagination with numbers


I'm trying to integrate a custom pagination component with Swiper with no success.

The custom pagination component renders a prev and a next button with also the number of the current slide and the total number of pages:

type ArrowPaginationProps = {
  current: number;
  total: number;
  onClickPrev: () => void;
  onClickNext: () => void;
};

export const ArrowPagination = (props: ArrowPaginationProps) => {
  return (
    <div className="arrow-pagination">
      <button type="button" onClick={props.onClickPrev}>
        Prev
      </button>
      <div className="arrow-pagination-label">
        {props.current} / {props.total}
      </div>
      <button type="button" onClick={props.onClickNext}>
        Next
      </button>
    </div>
  );
};

And this what I've done to integrate it with swiper:

import React, { useState } from "react";
// Import Swiper React components
import { Swiper, SwiperSlide, SwiperClass } from "swiper/react";
import { Controller } from "swiper/modules";
import { ArrowPagination } from "./ArrowPagination";

// Import Swiper styles
import "swiper/css";

import "./styles.css";

export default function App() {
  const [controlledSwiper, setControlledSwiper] = useState<SwiperClass>(null);

  const handleClickPrev = () => controlledSwiper.slidePrev();
  const handleClickNext = () => controlledSwiper.slideNext();

  return (
    <>
      <Swiper
        modules={[Controller]}
        controller={{ control: controlledSwiper }}
        onSwiper={setControlledSwiper}
      >
        {slides.map((text, idx) => {
          return <SwiperSlide key={idx}>{text}</SwiperSlide>;
        })}
        <div slot="container-end">
          <ArrowPagination
            current={controlledSwiper?.activeIndex + 1}
            total={slides.length}
            onClickPrev={handleClickPrev}
            onClickNext={handleClickNext}
          />
        </div>
      </Swiper>
    </>
  );
}

const slides = [
  "Slide 1",
  "Slide 2",
  "Slide 3",
  "Slide 4",
  "Slide 5",
  "Slide 6",
  "Slide 7",
  "Slide 8",
  "Slide 9",
  "Slide 10",
];

The issue is that, when I click the prev or next button, the current page number is not being updated.

Reproducible sandbox here: https://codesandbox.io/p/sandbox/react-swipper-custom-pagination-hq73hw


Solution

  • Try this approach:

    import React, { useState } from "react";
    import { Swiper, SwiperSlide, SwiperClass } from "swiper/react";
    import { Controller } from "swiper/modules";
    import { ArrowPagination } from "./ArrowPagination";
    import "swiper/css";
    import "./styles.css";
        
    export default function App() {
      const [controlledSwiper, setControlledSwiper] = useState<SwiperClass>(null);
      const [activeIndex, setActiveIndex] = useState(0);
        
      const handleClickPrev = () => controlledSwiper.slidePrev();
      const handleClickNext = () => controlledSwiper.slideNext();
        
      const handleSlideChange = () => {
        setActiveIndex(controlledSwiper?.activeIndex || 0);
      };
        
      return (
        <>
          <Swiper
            modules={[Controller]}
            controller={{ control: controlledSwiper }}
            onSwiper={setControlledSwiper}
            onSlideChange={handleSlideChange}
          >
            {slides.map((text, idx) => {
              return <SwiperSlide key={idx}>{text}</SwiperSlide>;
            })}
          </Swiper>
          <ArrowPagination
            current={activeIndex + 1}
            total={slides.length}
            onClickPrev={handleClickPrev}
            onClickNext={handleClickNext}
          />
        </>
      );
    }
    

    https://codesandbox.io/p/sandbox/react-swipper-custom-pagination-forked-vp7l7f?file=%2Fsrc%2FApp.tsx