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>
);
}
#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.