Рейл категорий для вашего магазина на React
Рейлы категорий — тапабельный ряд разделов над сеткой витрины — это самые посещаемые контейнеры прокрутки в e-commerce, и они меню, а не карусели: каждая плитка — это ссылка, ничто не прилипает к позиции, а половина плитки, выглядывающая из-за края, и есть приглашение прокрутить.
Перетащите рейл или используйте стрелки — они отключаются на настоящих концах ряда.
Редактировать этот пример вживую в Storybook
Почему нативная прокрутка побеждает на витрине
Рейлы витрины живут в первом экране страниц, где вы боретесь за каждый балл Lighthouse. Карусельный движок поставляет десятки килобайт эмуляции жестов, чтобы делать то, что браузер делает нативно; эта библиотека — ≈5.7 kB min+gzip и оставляет прокрутку платформе, поэтому нет рывков гидратации — рейл прокручивается ещё до загрузки вашего JavaScript, а значит, работает и в серверно отрендеренном HTML, который видят краулеры. Эта страница сама служит серверным доказательством: демо выше прокручивается при отключённом JavaScript.
На странице сравнения есть полная таблица против Swiper, Embla, keen-slider и react-slick.
Отслеживание видимости — это функция витрины
Видимость по каждому элементу звучит как деталь реализации, пока вы не спроецируете её на мерчандайзинг:
- Ленивые изображения — рендерите плитку-заглушку, пока
useIsVisibleне сообщит, что она на экране. - Аналитика показов —
getVisible()(работает в демо в шапке на главной странице) сообщает точно, какие категории были увидены, а не просто что рейл отрендерился. - Стрелки, учитывающие края — отключаются или скрываются на настоящих концах, даже после асинхронной загрузки категорий, как в примере add-items.
Впишите его в вашу дизайн-систему
Плитки — это ваши компоненты: карточки с изображениями, круги, текстовые «пилюли» — каждая несёт itemId. Высота и ширина берутся из вашего CSS; меню не навязывает размеров. Шагайте по одному элементу за раз, как в товарном слайдере, с помощью one-item-scroll, покажите индикатор прогресса прокрутки или отправьте его в RTL для арабских и ивритских магазинов с помощью примера RTL — рейл это композиция, а не конфигурация.
Паттерн в минимальном виде
Плитки с itemId, стрелки из хуков видимости — весь рейл укладывается в сорок строк.
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 — это и есть данный рейл: стрелки в стиле shadcn, перетаскивание для прокрутки, скрытая полоса прокрутки — устанавливается в вашу components/ui/ и стилизуется вашими токенами:
npx shadcn@latest add https://react-horizontal-scrolling-menu.dev/r/scroll-menu.json