その横メニューは、何が見えているかを知っている

ブラウザ自身のスクロール上に構築された React スクロールメニュー——項目ごとの可視性追跡、矢印、ドラッグ、そして完全な命令型 API。gzip で 5.7 kB

Sci-Fi
Comedy
Drama
Horror
Docs
Kids
Action
Indie
Anime
Classics
Thriller
Reality

getVisible() → ['scifi', 'comedy', 'drama', 'horror', 'docs', 'kids']

This is the library, live — drag it. Dimmed tiles are the ones useIsVisible reports as off-screen.

npm install react-horizontal-scrolling-menu347k ダウンロード/月5.7 kB min+gzipReact 16.8 – 19MIT

カルーセルエンジンなしの自動再生

autoplay プロパティはありません。このレールは公開 API 上のレシピです。行を両端にクローンし、継ぎ目で 1 回 scrollLeft をジャンプさせ、scrollNext() を呼ぶタイマーを回します。ホバー、フォーカス、非表示タブで一時停止し、動きを減らす設定下では静止します。継ぎ目をまたいで、逆向きにさえドラッグできます。

Tokyo
Oslo
Lima
Cairo
Sydney
Quito
Seoul
Porto
Denver
Hanoi

メニューであり、カルーセルではない

Embla、Swiper、keen-slider は、画像スライダーを作るために JavaScript でスクロールを再実装しています——スナップポイント、スプリング物理、レンダーループ。このライブラリはそのどれも同梱しません。ブラウザネイティブのスクロールに乗り、ブラウザが与えない 1 つ——どの項目が画面上にあるかの把握を加えます。

全画面画像スライダーにとっては 間違った道具——そこでは Embla か Swiper を。カテゴリー行、タブストリップ、チップフィルター、そしてアプリが把握する必要のあるあらゆる行にとっては、正しい道具

ネイティブスクロール

慣性、スクロールバー、タッチ、ホイール、アクセシビリティは、物理エンジンではなくブラウザから得られます。JavaScript がハイドレートする前からこの行はスクロールできます——このページのすべてのデモはサーバーレンダリングされます。

可視性追跡

IntersectionObserver がどの項目が画面上にあるかを報告します。useIsVisible(itemId) は 1 つのコンポーネントを 1 つの項目に購読させます——スクロール位置の計算は不要で、影響を受けた項目だけが再レンダリングされます。

必要なときは命令型

scrollToItemscrollNextscrollPrev、id やインデックスでの検索——メニュー内のコンテキストを通じて、あるいは外部から apiRef で。

あなたのコンポーネント、あなたの CSS

矢印、ヘッダー、フッター、そしてすべての項目はあなたが書くコンポーネントです。項目の幅はあなたの CSS。ライブラリが同梱するのは 210 バイトのレイアウトスタイルだけで、邪魔をしません。

クイックスタート

1 ファイル、設定不要:itemId を持つ項目、VisibilityContext を読む 2 つの矢印、そしてスタイルシートのインポート。

App.tsx
import React from 'react';
import {
  ScrollMenu,
  VisibilityContext,
  type publicApiType,
} from 'react-horizontal-scrolling-menu';
import 'react-horizontal-scrolling-menu/dist/styles.css';

const items = Array.from({ length: 10 }, (_, i) => `item-${i + 1}`);

export function App() {
  return (
    <ScrollMenu LeftArrow={LeftArrow} RightArrow={RightArrow}>
      {items.map((id) => (
        <Card itemId={id} key={id} title={id} />
      ))}
    </ScrollMenu>
  );
}

function LeftArrow() {
  const visibility = React.useContext<publicApiType>(VisibilityContext);
  const isFirstVisible = visibility.useIsVisible('first', true);
  return (
    <button
      disabled={isFirstVisible}
      onClick={() => visibility.scrollPrev()}
    >

    </button>
  );
}

function RightArrow() {
  const visibility = React.useContext<publicApiType>(VisibilityContext);
  const isLastVisible = visibility.useIsVisible('last', false);
  return (
    <button
      disabled={isLastVisible}
      onClick={() => visibility.scrollNext()}
    >

    </button>
  );
}

function Card({ itemId, title }: { itemId: string; title: string }) {
  const visibility = React.useContext<publicApiType>(VisibilityContext);
  const isVisible = visibility.useIsVisible(itemId);
  return (
    <div className="card" data-visible={isVisible}>
      <div>{title}</div>
      <div>visible: {String(isVisible)}</div>
    </div>
  );
}

The code on the left, running:

item-1
visible: true
item-2
visible: true
item-3
visible: true
item-4
visible: false
item-5
visible: false
item-6
visible: false
item-7
visible: false
item-8
visible: false
item-9
visible: false
item-10
visible: false

itemId はすべての項目に必須です——追跡はこれで動きます。React の key はフォールバックとして機能します。

styles.css は別途インポートします。JS バンドルが CSS を注入することはありません。

項目の幅はあなた自身の CSS で決まります——メニューが計測することはありません。

完全な入門例を読む

またはコーディングエージェントに任せる

古いリリースで学習したモデルは、visibleElementsSeparator 項目、Arrows プロパティ——すべて何年も前に削除済み——に今も手を伸ばし、存在したことのない autoplay プロパティをでっち上げます。このパッケージにはそれを止めるための 8 つの SKILL.md ファイルが同梱されています。タスクスコープのガイダンスで、エージェントが TanStack Intent を通じてオンデマンドで読み込み、このページではなくライブラリとともにバージョン管理されます。

npx @tanstack/intent@latest install

パッケージが既にインストールされているプロジェクトで一度実行します。その後エージェントは node_modules/react-horizontal-scrolling-menu/skills/ からスキルを発見します。

  • menu-setup最初の動作するメニュー、矢印、必要な CSS インポート
  • menu-visibility画面上の内容と、端での矢印の状態
  • menu-scrollingscrollToItem、apiRef、1 ページずつのページング
  • menu-interactionsドラッグ、ホイール、タッチ——とそれらのハンドラーファクトリー
  • menu-recipes自動再生、無限ループ、追加読み込み:プロパティではなくレシピ
  • menu-transitions-rtlアニメーションのタイミング、カスタムイージング、右から左
  • menu-testing-ssrNext.js と RSC、Jest モック、Playwright
  • menu-migrationv8 以前のコードのアップグレードと、モデルが今もでっち上げる API

箱の中身

  • 項目ごとの可視性フック——useIsVisible(itemId)
  • 矢印状態のための first / last ヘルパー
  • scrollToItem · scrollNext · scrollPrev
  • メニューの外から制御する apiRef
  • ドラッグ、ホイール、タッチ、スクロールバーの入力
  • 動的な追加/削除の検出
  • Header と Footer のスロット
  • slidingWindow + getItemsPos のページングヘルパー
  • 右から左のサポート
  • カスタムトランジション関数
  • SSR セーフ——このページが証明
  • TypeScript ファースト——publicApiType をエクスポート
  • React 16.8 – 19 で 1 つの安定した API

箱の中身にないもの

  • スナップとスプリング物理
  • 全画面画像スライダー
  • ライトボックス

それは画像スライダーの領域です——Embla と Swiper が上手にこなします。無限ループ自動再生 もプロパティではありません——レシピです。それぞれ公開 API の約 60 行で、Storybook でライブ編集できます。このページ上部のレールは、まさにそのレシピが動いているものです。これはメニューのままです。

先月 347,516 回、約 20,000 のリポジトリにダウンロードされました——2018 年から保守。

GitHub で 788 スターReact Status #257 で紹介Our World in Data で本番利用

すべての例をブラウザーで編集できる

Storybook はプレイグラウンドを兼ねます。各ストーリーにはライブラリの実際の型定義を読み込んだ Monaco エディターが付属します。コードを変えて、再レンダリングを眺める——サンドボックスアカウントもローカルセットアップも不要です。

Aleksandr Smyshliaev が構築・保守

2018 年に初公開。React 16.8 から 19 まで同じ公開 API。Aleksandr はフロントエンドエンジニア(React、Next.js、TypeScript)で、現在、契約および正社員の仕事を募集中です。