---
title: "Рейл категорий React для e-commerce"
description: "Горизонтальный рейл категорий в React: нативная прокрутка, стрелки, отключающиеся у краёв, видимость по элементам для ленивых изображений и аналитики. Демо и код."
canonical: "https://react-horizontal-scrolling-menu.dev/ru/category-rail"
image: "https://react-horizontal-scrolling-menu.dev/og.png"
---

# Рейл категорий для вашего магазина на React

Рейлы категорий — тапабельный ряд разделов над сеткой витрины — это самые посещаемые контейнеры прокрутки в e-commerce, и они меню, а не карусели: каждая плитка — это ссылка, ничто не прилипает к позиции, а половина плитки, выглядывающая из-за края, и есть приглашение прокрутить.

TTokyo

OOslo

LLima

CCairo

SSydney

QQuito

SSeoul

PPorto

DDenver

HHanoi

Перетащите рейл или используйте стрелки — они отключаются на настоящих концах ряда.

[Редактировать этот пример вживую в Storybook](https://asmyshlyaev177.github.io/react-horizontal-scrolling-menu/?path=/story/examples-simple--simple)

## Почему нативная прокрутка побеждает на витрине

Рейлы витрины живут в первом экране страниц, где вы боретесь за каждый балл Lighthouse. Карусельный движок поставляет десятки килобайт эмуляции жестов, чтобы делать то, что браузер делает нативно; эта библиотека — ≈5.7 kB min+gzip и оставляет прокрутку платформе, поэтому нет рывков гидратации — рейл прокручивается ещё до загрузки вашего JavaScript, а значит, работает и в серверно отрендеренном HTML, который видят краулеры. Эта страница сама служит серверным доказательством: демо выше прокручивается при отключённом JavaScript.

На [странице сравнения](https://react-horizontal-scrolling-menu.dev/ru/compare.md) есть полная таблица против Swiper, Embla, keen-slider и react-slick.

## Отслеживание видимости — это функция витрины

Видимость по каждому элементу звучит как деталь реализации, пока вы не спроецируете её на мерчандайзинг:

-   **Ленивые изображения** — рендерите плитку-заглушку, пока `useIsVisible` не сообщит, что она на экране.
-   **Аналитика показов** — `getVisible()` (работает в [демо в шапке](https://react-horizontal-scrolling-menu.dev/ru.md) на главной странице) сообщает точно, какие категории были увидены, а не просто что рейл отрендерился.
-   **Стрелки, учитывающие края** — отключаются или скрываются на настоящих концах, даже после асинхронной загрузки категорий, как в [примере add-items](https://react-horizontal-scrolling-menu.dev/ru/examples/add-items.md).

## Впишите его в вашу дизайн-систему

Плитки — это ваши компоненты: карточки с изображениями, круги, текстовые «пилюли» — каждая несёт `itemId`. Высота и ширина берутся из вашего CSS; меню не навязывает размеров. Шагайте по одному элементу за раз, как в товарном слайдере, с помощью [one-item-scroll](https://react-horizontal-scrolling-menu.dev/ru/examples/one-item-scroll.md), покажите [индикатор прогресса](https://react-horizontal-scrolling-menu.dev/ru/examples/progress.md) прокрутки или отправьте его в RTL для арабских и ивритских магазинов с помощью [примера RTL](https://react-horizontal-scrolling-menu.dev/ru/examples/rtl.md) — рейл это композиция, а не конфигурация.

## Паттерн в минимальном виде

Плитки с `itemId`, стрелки из хуков видимости — весь рейл укладывается в сорок строк.

CategoryRail.tsx

```
function CategoryRail({ categories }: { categories: Category[] }) {
  return (
    <ScrollMenu LeftArrow={LeftArrow} RightArrow={RightArrow}>
      {categories.map((category) => (
        <CategoryTile itemId={category.id} key={category.id} {...category} />
      ))}
    </ScrollMenu>
  );
}

function CategoryTile({ itemId, name, image }: CategoryTileProps) {
  // Lazy images for free: placeholders until the tile is on screen.
  const visibility = React.useContext<publicApiType>(VisibilityContext);
  const isVisible = visibility.useIsVisible(itemId, false);
  return (
    <a href={`/category/${itemId}`} className="rail-tile">
      {isVisible ? <img src={image} alt="" /> : <div className="ph" />}
      <span>{name}</span>
    </a>
  );
}

function LeftArrow() {
  const visibility = React.useContext<publicApiType>(VisibilityContext);
  const atStart = visibility.useLeftArrowVisible();
  return (
    <button disabled={atStart} onClick={() => visibility.scrollPrev()}>
      ←
    </button>
  );
}
```

## Или установите как компонент shadcn

Базовый элемент реестра [scroll-menu](https://react-horizontal-scrolling-menu.dev/r/scroll-menu.json) — это и есть данный рейл: стрелки в стиле shadcn, перетаскивание для прокрутки, скрытая полоса прокрутки — устанавливается в вашу `components/ui/` и стилизуется вашими токенами:

shadcn

```
npx shadcn@latest add https://react-horizontal-scrolling-menu.dev/r/scroll-menu.json
```

## Похожие примеры

-   [Начало работыМинимальное меню: элементы, две стрелки, видимость из коробки.](https://react-horizontal-scrolling-menu.dev/ru/examples/simple.md)
-   [Прокрутка по одному элементуСтрелки продвигают один элемент вместо целой страницы.](https://react-horizontal-scrolling-menu.dev/ru/examples/one-item-scroll.md)
-   [Индикатор прогресса прокруткиПолоса прогресса, управляемая тем, какие элементы видны.](https://react-horizontal-scrolling-menu.dev/ru/examples/progress.md)

[Все примеры (21)](https://react-horizontal-scrolling-menu.dev/ru/examples.md)

---

More examples: <https://react-horizontal-scrolling-menu.dev/examples.md>
Library summary for LLMs: <https://react-horizontal-scrolling-menu.dev/llms.txt>
