🛝

カルーセルスライダーライブラリの Embla Carousel が良かった

2024/07/07に公開

WEBサイトの開発でカルーセルスライダーを実装する際に、Swiper によくお世話になっています。
はじめての OSS コントリビュートも Swiper でした。

https://github.com/nolimits4web/swiper/pull/7228

https://github.com/nolimits4web/swiper/pull/7319

Swiperも優れたライブラリで気に入っていますが、React / TypeScript の構成で利用する際にコンポーネントではなくロジックだけ提供するライブラリがないかなと思い調べてみたところ、以下記事で Embla Carousel の存在を知りました。

https://zenn.dev/nihashi/articles/9085dc4ba68117

自分でも実際に使ってみて満足感が高かったのでかんたんにご紹介します。

サンプル

記事でご紹介する内容よりもう少し詳細なコンポーネントのサンプルは以下リポジトリにあげております。
※ロジックは useCarousel というカスタムフックで切り出しています。

https://github.com/yasuhiro-yamamoto/nextjs-playground/tree/main/src/components/Carousel

プロジェクトに Embla Carousel を追加後、利用するコンポーネントでインポートします。

import useEmblaCarousel from 'embla-carousel-react'

embla-carousel-reactはカルーセルスライダーの対象とする要素に渡すrefとスライダーの各種メソッドにアクセスするAPIを返します。

import useEmblaCarousel from "embla-carousel-react";
import styles from "./style.module.scss"

export const EmblaCarousel: React.FC = () => {
  const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true })

  const handleNext = () => {
    if (!emblaApi || !emblaApi.canScrollNext()) return;

    console.log('next');
    emblaApi.scrollNext();
  }

  const handlePrev = () => {
    if (!emblaApi || !emblaApi.canScrollPrev()) return;

    console.log('next');
    emblaApi.scrollPrev();
  }

  return (
    <section className={styles.container}>
      <h2>Slider</h2>

      <div className={styles.slider} ref={emblaRef}>
        <div className={styles.sliderList}>
          <div className={styles.sliderItem}>Slide 1</div>
          <div className={styles.sliderItem}>Slide 2</div>
          <div className={styles.sliderItem}>Slide 3</div>
        </div>
      </div>

      <div className={styles.sliderControls}>
        <button type="button" onClick={handlePrev}>Prev</button>
        <button type="button" onClick={handleNext}>Next</button>
      </div>
    </section>
  )
}

TypeScript 製のライブラリのため VSCode で補完も効いてくれます。
利用可能なメソッドや指定可能なオプションなどの詳細は公式のドキュメントをご確認ください。

https://www.embla-carousel.com/api/

スタイルは自分で実装する

個人的にはここが気に入った点となりますが、スタイルは自分自身で柔軟な実装が可能です。

.container {
  width: min(700px, 90%);
  margin-inline: auto;
  display: grid;
  grid-auto-rows: auto;
  gap: 20px;
}

.sliderControls {
  display: flex;
  justify-content: center;
  gap: 10px;
}

button {
  border: 1px solid #ccc;
}

h2 {
  text-align: center;
}

/* スライドのコンテナ(他のスライドが見えないようにする) */
.slider {
  overflow: hidden;
}

/* スライドの一覧を横並びにする */
.sliderList {
  display: flex;
}

/* 表示枚数は flex-basis で親コンテナのサイズに対して割合指定(例えば2枚表示なら50%) */
.sliderItem {
  flex: 0 0 100%;
  min-width: 0;
  aspect-ratio: 16/9;
  background-color: #f7f7f7;
  display: grid;
  place-content: center;
}

結果

以下のようにシンプルなスライダーがこれだけで実装できました。

スライダーを操作する様子

サンプルサイトで動作確認する

おわりに

柔軟な指定が可能という意味で個人的にはとても気に入りました。
今後実際の業務でも要件が合う場合は採用してみたいと思います。

Discussion