Carousel
ネイティブのスクロールスナップによるスライドです。タッチでの慣性、マウスドラッグ、矢印キー、ドット、サムネイル、適切なタイミングで一時停止する自動再生に対応します。
pnpm dlx shadcn@latest add https://hextaui.com/r/carousel.jsonコンポーネント、HextaUIのテーマトークン、依存するHextaUIコンポーネントを追加します。
まだ追加していない場合は、グローバルCSSにテーマトークンを追加してください。
依存関係をインストールします。
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cn次のコードをコピーしてプロジェクトに貼り付けてください。
components/ui/carousel.tsx components/ui/button.tsx components/ui/number-flow.tsx lib/motion.ts インポートパスは、お使いのプロジェクト構成に合わせて更新してください。
スライドは CSS のスクロールスナップでネイティブにスクロールするため、タッチの慣性やトラックパッドのスクロールがプラットフォームの感覚どおりになります。マウスでドラッグでき、矢印キーで 1 枚ずつ移動します。
API
setApi を渡してカルーセルの API を取得し、select をリッスンして独自の位置を表示します。最後のスライドでは Next が無効になりますが、フォーカスは保たれます。
1 画面に複数表示
各項目は独自の basis を設定します。余白は spacing prop で決まるため、どの basis でも正確に保たれます。
ドットとカウンター
アクティブなドットはスライドのスクロールに合わせて伸び、隣のドットは場所を空けます。カウンターは、変化した桁だけを回転させます。
自動再生
autoplay はデフォルトでオフで、モーションの低減が有効な場合もオフのままです。ホバー、キーボードフォーカス、タッチ、ドラッグ、非表示のタブ、画面外へのスクロールで一時停止し、タイマーの進行に合わせてアクティブなドットが満たされます。
サムネイル
<CarouselThumbnails /> はメインのカルーセルに追従し、アクティブなサムネイルが見えるようスクロールします。
垂直
orientation="vertical" には、<CarouselContent /> に高さの指定が必要です。ボタンは上下に移動します。
制御
index と onIndexChange を渡します。スワイプすると state が更新され、state の変更でカルーセルがスクロールします。
巻き戻しと開始インデックス
rewind は、最後のスライドで Next を押すと最初のスライドに戻します。defaultIndex は、スクロールアニメーションなしでスライドを開きます。
リンクとフォーカス可能なコンテンツ
マウスでリンクをドラッグすると、リンクを開かずにスクロールします。画面外のスライドにタブで移動すると、そのスライドが表示位置までスクロールされます。
スライドの追加と削除
スライドの増減に合わせて、ドット、カウンター、ボタンが更新されます。
入れ子
矢印キー、ドラッグ、ドットは、操作中のカルーセルだけを動かします。
長いコンテンツと単一のスライド
区切りのないテキストはスライド内で折り返されます。スライドが 1 枚の場合、ドットは非表示になり、ボタンは無効のままです。
右から左
スライドは右から始まり、矢印が反転し、左矢印キーで前に進み、ドットは右から埋まります。
キーは、テキスト入力欄とネストしたカルーセルを除き、カルーセル内のどこにフォーカスがあっても動作します。
| キー | アクション |
|---|---|
| → | 次のスライド。右から左のレイアウトでは前のスライド。縦向きのカルーセルでは ↓。 |
| ← | 前のスライド。右から左のレイアウトでは次のスライド。縦向きのカルーセルでは ↑。 |
| Tab | ボタン、アクティブなドット、スライド内のコンテンツの間を移動し、画面外のスライドは表示位置までスクロールされます。 |
| EnterSpace | フォーカス中のボタン、ドット、サムネイルを実行します。 |
- ルートは、カルーセルとして説明される
regionです。aria-labelを付けてください。 - 各項目は、スライドとして説明され、「3 of 5」のように位置のラベルが付く
groupです。 - キーボードやボタンによる移動の後は、polite なライブリージョンが新しいスライドを通知し、自動再生の間は通知しません。
- ドットとサムネイルは 1 つのタブストップを使い、フォーカスはアクティブなものに追従します。
- Previous と Next は無効でもフォーカス可能なままなので、どちらの端でもフォーカスが失われません。
| プロパティ | 型 | デフォルト |
|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" |
spacingスライド間の余白。 | "none" | "sm" | "default" | "lg" | "default" |
index | number | – |
defaultIndex | number | 0 |
onIndexChange | (index: number) => void | – |
rewind最後のスライドから最初のスライドに戻ります。 | boolean | false |
mouseDragマウスでスライドをドラッグできるようにします。 | boolean | true |
autoplayタイマーで進めます。delay のデフォルトは 5000ms で、最小は 1000ms です。 | boolean | { delay?: number } | false |
setApi | (api: CarouselApi) => void | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| 属性 | 説明 |
|---|---|
data-slot="carousel" | CSSでルートを指定します。 |
data-orientation | 向き。 |
--carousel-spacing | spacing で設定されるスライド間の余白。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
classNameスライドを保持するトラックに適用されます。 | string | – |
viewportClassNameスクロールするビューポートに適用されます。 | string | – |
| 属性 | 説明 |
|---|---|
data-slot="carousel-content" | スクロールするビューポート。 |
data-slot="carousel-container" | その内側のトラック。 |
data-scrollable | 位置が 2 つ以上あるときに付与されます。 |
data-dragging | マウスでのドラッグ中に付与されます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <div> |
| 属性 | 説明 |
|---|---|
data-slot="carousel-item" | basis-* を設定すると、1 画面に複数のスライドを表示できます。 |
どちらも <Button /> をレンダリングし、その props を受け付けます。コンテンツの外側に配置されるため、カルーセルの周囲に余白を確保してください。
| プロパティ | 型 | デフォルト |
|---|---|---|
variant | ButtonProps["variant"] | "outline" |
size | ButtonProps["size"] | "icon-sm" |
children向きと方向に従います。 | ReactNode | Arrow icon |
| 属性 | 説明 |
|---|---|
data-slot="carousel-previous" | 「Previous slide」というラベルが付きます。 |
data-slot="carousel-next" | 「Next slide」というラベルが付きます。 |
data-disabled | どちらかの端で付与されます。ボタンはフォーカス可能なままです。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
aria-label | string | "Choose slide" |
| 属性 | 説明 |
|---|---|
data-slot="carousel-dots" | ドットのグループ。位置が 1 つの場合は非表示になります。 |
data-slot="carousel-dot" | 各ドット。アクティブなものには aria-current が付きます。 |
--dot-active | 0 から 1。スクロール中のドットのアクティブ度。 |
| 属性 | 説明 |
|---|---|
data-slot="carousel-counter" | 現在の位置と全体の数を、回転する数字で表示します。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
variant | ButtonProps["variant"] | "ghost" |
size | ButtonProps["size"] | "icon-sm" |
| 属性 | 説明 |
|---|---|
data-slot="carousel-autoplay-toggle" | 「Pause slideshow」または「Play slideshow」というラベルが付きます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
aria-label | string | "Slides" |
| 属性 | 説明 |
|---|---|
data-slot="carousel-thumbnails" | スクロールするストリップ。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
index開くスライド。デフォルトは、ストリップ内での位置です。 | number | – |
render | ReactElement | (props, state) => ReactElement | <button> |
| 属性 | 説明 |
|---|---|
data-slot="carousel-thumbnail" | CSS でサムネイルを指定します。 |
data-active | スライドが表示されている間、付与されます。 |
setApi と useCarousel() を通じて返されます。アニメーションなしで移動するには jump: true を渡します。
| プロパティ | 型 | デフォルト |
|---|---|---|
scrollPrev | (jump?: boolean) => void | – |
scrollNext | (jump?: boolean) => void | – |
scrollToスナップ位置までスクロールします。 | (index: number, jump?: boolean) => void | – |
scrollToSlideスライドが表示される位置までスクロールします。 | (slideIndex: number, jump?: boolean) => void | – |
canScrollPrev | () => boolean | – |
canScrollNext | () => boolean | – |
selectedScrollSnap | () => number | – |
scrollSnapList | () => number[] | – |
slidesInView | () => number[] | – |
slideNodes | () => HTMLElement[] | – |
viewportNode | () => HTMLElement | null | – |
play | () => void | – |
stop | () => void | – |
isPlaying | () => boolean | – |
on / off | (event: "select" | "scroll" | "settle" | "reInit", listener) => CarouselApi | – |
独自のコントロールを作るには <Carousel /> の内側で使います。api、orientation、selectedIndex、snapCount、slideCount、slidesInView、canScrollPrev、canScrollNext、isPlaying と、スクロールと再生のメソッドを返します。
- Buttonすべてのバリアントとサイズのボタンです。読み込み、成功、エラーのフローを内蔵し、高速なリクエストではスピナーを省略します。
- Number flow変化した桁だけが回転するアニメーション付きの数値です。任意のIntlフォーマットとロケールに対応します。
- Accordionそれぞれがパネルを表示する見出しの積み重ねです。途中で反転できる高さのモーションを持ち、閉じている間もパネルの内容を検索できます。
- Aspect ratioメディアの読み込み前も形を保ち、読み込み中はシマー表示になり、メディアをフェードインさせ、失敗時はフォールバックを表示するボックスです。
- Collapsible高さのモーションで表示と非表示を切り替えるパネルです。途中で反転でき、レイアウトが跳ねません。
- Resizableドラッグで分割できるパネルです。ホバーで目覚める控えめな区切り線、リセットや折りたたみで滑らかに動くサイズ、永続化されるレイアウトに対応します。