---
title: "Фильтр-чипы React в прокручиваемой панели"
description: "Горизонтальная панель фильтр-чипов в React: чипы прокручиваются нативно, добавление чипа прокручивает его в область видимости, перетаскивание не ломает клики. Живая демонстрация и код."
canonical: "https://react-horizontal-scrolling-menu.dev/ru/filter-chips"
image: "https://react-horizontal-scrolling-menu.dev/og.png"
---

# Прокручиваемая панель фильтр-чипов в React

Ряд чипов под любой строкой поиска — темы YouTube, фильтры магазина, выбор тегов — это однострочный контейнер прокрутки, заполненный кнопками-переключателями. Сложные 10% — это то, что происходит по краям: новые чипы, появляющиеся вне экрана, перетаскивания, которые не должны ничего переключать, и стрелки, знающие, когда они бесполезны.

react

typescript

scrolling

menu

gallery

tabs

carousel

slider

accordion

lightbox

Add filter

Добавьте фильтр — ряд сам прокрутит новый чип в область видимости.

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

## Крайние случаи и есть та самая функциональность

Прокручивается любой flex-ряд с `overflow-x: auto`. Панель чипов оправдывает себя именно деталями:

-   **Чип, добавленный вне экрана, должен заявить о себе.** Демо прокручивает к каждому новому чипу с помощью `apiRef.current.scrollToItem(el, 'smooth', 'end')` после рендера — [пример add-item-and-scroll-to-it](https://react-horizontal-scrolling-menu.dev/ru/examples/add-item-and-scroll-to-it.md) реализует именно это.
-   **Перетаскивание для прокрутки, клик для переключения — никогда одновременно.** Пользователи десктопа перетаскивают ряд как тач-поверхность; отпускание над чипом не должно его переключать. [Рецепт перетаскивания](https://react-horizontal-scrolling-menu.dev/ru/examples/mouse-drag.md) отслеживает жест и подавляет именно этот клик.
-   **Стрелки только тогда, когда они полезны.** `useLeftArrowVisible` / `useRightArrowVisible` подключены к тому же IntersectionObserver, что и всё остальное, поэтому стрелки отключаются на настоящих краях — в том числе после добавления или удаления чипов.

## Состояние остаётся в ваших руках

Библиотека прокручивает; она не владеет выбором. Чипы — это ваши кнопки: `aria-pressed` для переключателей с множественным выбором, обычное состояние для одиночного выбора — меню нужно лишь, чтобы у каждого был `itemId`. Это значит, что состояние чипов сочетается с тем, что у вас уже есть: параметрами URL, библиотекой форм, серверной моделью фильтров. Удаление чипа — это [удаление элемента](https://react-horizontal-scrolling-menu.dev/ru/examples/add-items.md); анимированное исчезновение — [пример items-animation](https://react-horizontal-scrolling-menu.dev/ru/examples/items-animation.md).

## Мобильные устройства: одно предупреждение о прокрутке страницы

На сенсорных экранах горизонтальный свайп внутри панели в некоторых браузерах может утянуть за собой страницу вбок. Если вы столкнулись с этим, [пример prevent-body-scroll](https://react-horizontal-scrolling-menu.dev/ru/examples/prevent-body-scroll.md) показывает `touch-action` и сдерживание overscroll, чтобы это заблокировать — только CSS, без библиотеки жестов.

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

Чипы — это кнопки-переключатели с `itemId`; ref на API меню прокручивает вновь добавленный чип в область видимости.

ChipBar.tsx

```
function ChipBar({ options }: { options: string[] }) {
  const apiRef = React.useRef<publicApiType>(null);
  const [selected, setSelected] = React.useState<string[]>([]);

  const toggle = (id: string) =>
    setSelected((cur) =>
      cur.includes(id) ? cur.filter((c) => c !== id) : [...cur, id],
    );

  // A chip appended off-screen scrolls itself into view.
  const addChip = (id: string) => {
    toggle(id);
    requestAnimationFrame(() => {
      const el = apiRef.current?.getItemElementById(id);
      if (el) apiRef.current?.scrollToItem(el, 'smooth', 'end');
    });
  };

  return (
    <ScrollMenu apiRef={apiRef}>
      {options.map((id) => (
        <Chip itemId={id} key={id} pressed={selected.includes(id)}
          onToggle={() => toggle(id)} />
      ))}
    </ScrollMenu>
  );
}
```

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

Элемент реестра [chip-bar](https://react-horizontal-scrolling-menu.dev/r/chip-bar.json) поставляет это в виде управляемого компонента — `options`, `selected`, `onSelectedChange` — стилизованного через Tailwind в вашей `components/ui/`:

shadcn

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

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

-   [Добавить элемент и прокрутить к немуПаттерн чипов-фильтров: добавить, затем привести в видимость.](https://react-horizontal-scrolling-menu.dev/ru/examples/add-item-and-scroll-to-it.md)
-   [Подгружать, когда виден конецБесконечное добавление, управляемое видимостью последнего элемента.](https://react-horizontal-scrolling-menu.dev/ru/examples/add-items.md)
-   [Заблокировать прокрутку страницыКолесо над меню прокручивает меню, а не страницу.](https://react-horizontal-scrolling-menu.dev/ru/examples/prevent-body-scroll.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>
