Today I learned about integrating Swiper Web Component with React + TypeScript.

In one of our projects, I needed to implement a carousel — something simple, clean, and flexible. I’ve used Swiper before, so I naturally reached for it. But this time, I noticed something new:

The React version might be deprecated in the future.

That got me curious. So instead of sticking with the React wrapper, I decided to explore the Web Component API that Swiper now provides.

It turns out, using it in React is quite straightforward — you just need to define the custom element, ensure TypeScript knows it, and use it like a normal JSX tag. The performance feels solid, and I actually like how it keeps the implementation closer to the web platform.

It’s a small discovery, but I really enjoyed seeing how modern libraries are shifting towards framework-agnostic web components — and how React can still play nicely with them.

// Swiper.tsx
import * as React from 'react';
import {register} from 'swiper/element/bundle';
import {SwiperOptions, Swiper as SwiperClass} from 'swiper/types';

export type {SwiperClass};

// Typings for the web component
declare global {
  namespace JSX {
    interface IntrinsicElements {
      'swiper-container': SwiperContainerProps;
      'swiper-slide': SwiperSlideProps;
    }
  }

  interface SwiperContainerElement extends HTMLElement {
    initialize: () => void;
  }
}

// Define the specific props for swiper-container
interface SwiperContainerProps
  extends React.HTMLAttributes<SwiperContainerElement> {
  init?: string;
  ref?: React.MutableRefObject<SwiperContainerElement | null>;
}

// Define the specific props for swiper-slide
interface SwiperSlideProps extends React.HTMLAttributes<HTMLElement> {}

export type SwiperProps = React.PropsWithChildren<
  {
    ref?: React.MutableRefObject<SwiperContainerElement | null>;
  } & SwiperOptions
>;

export const Swiper = React.memo((props: SwiperProps) => {
  const fallbackSliderRef = React.useRef<SwiperContainerElement | null>(null);
  const swiperRef = props.ref || fallbackSliderRef;

  const {children, ...rest} = props;

  React.useEffect(() => {
    // Register Swiper web component
    register();

    // pass component props to parameters
    const params = {
      ...rest,
    };

    if (swiperRef.current) {
      // Assign it to swiper element
      Object.assign(swiperRef.current, params);

      // initialize swiper
      swiperRef.current.initialize();
    }
  }, [rest, swiperRef]);

  return (
    <swiper-container init="false" ref={swiperRef}>
      {children}
    </swiper-container>
  );
});

export const SwiperSlide = React.memo(
  (props: React.HTMLAttributes<HTMLElement>) => {
    const {children, ...rest} = props;

    return <swiper-slide {...rest}>{children}</swiper-slide>;
  }
);

React Swiper Component

import { Swiper, SwiperSlide } from 'path/to/Swiper.tsx';

export default function App() {
  return (
    <Swiper
      slidesPerView={3}
      breakpoints={{ 768: { slidesPerView: 4 } }}
      on={{
        slideChange: () => console.log('slide changed'),
        progress: (s, progress) => console.log(`progress is ${progress}`),
      }}
    >
      <SwiperSlide>Slide 1</SwiperSlide>
      <SwiperSlide>Slide 2</SwiperSlide>
      <SwiperSlide>Slide 3</SwiperSlide>
    </Swiper>
  );
}
React Swiper Web Component with Typescript
React Swiper Web Component with Typescript. GitHub Gist: instantly share code, notes, and snippets.

#TIL - Using `React` with `Swiper` Web Component (`TypeScript` Edition)

A small reflection on integrating Swiper’s Web Component in a React + TypeScript project — a step away from the React wrapper, and a peek into the future of reusable web components.