React로 만드는 스크롤되는 필터 칩 바
검색 바 아래에 있는 칩 행 — YouTube 주제, 스토어 필터, 태그 선택기 — 은 토글 버튼으로 가득한 한 줄짜리 스크롤 컨테이너입니다. 어려운 10%는 가장자리에서 일어나는 일들입니다: 화면 밖에 새로 나타나는 칩, 아무것도 토글해서는 안 되는 드래그, 그리고 스스로 무의미해질 때를 아는 화살표.
필터를 추가해보세요 — 새 칩이 보이도록 행이 스스로 스크롤됩니다.
엣지 케이스가 곧 기능입니다
overflow-x: auto가 걸린 flex 행은 무엇이든 스크롤됩니다. 칩 바의 진가는 디테일에서 드러납니다:
- 화면 밖에 추가된 칩은 스스로 존재를 알려야 합니다. 데모는 렌더링 후
apiRef.current.scrollToItem(el, 'smooth', 'end')로 새로 추가된 모든 칩으로 스크롤합니다 — add-item-and-scroll-to-it 예제가 정확히 이 연결을 보여줍니다. - 드래그하면 스크롤, 클릭하면 토글 — 절대 둘 다는 아닙니다. 데스크톱 사용자는 행을 터치 표면처럼 드래그하는데, 칩 위에서 손을 떼도 그 칩이 뒤집혀서는 안 됩니다. 드래그 레시피가 제스처를 추적해 그 한 번의 클릭만 억제합니다.
- 화살표는 쓸모 있을 때만.
useLeftArrowVisible/useRightArrowVisible은 다른 모든 것과 같은 IntersectionObserver에 연결되어 있으므로, 칩이 추가되거나 제거된 뒤에도 진짜 가장자리에서 화살표가 비활성화됩니다.
상태는 여러분의 손안에 있습니다
라이브러리는 스크롤을 담당할 뿐 선택 상태를 소유하지 않습니다. 칩은 여러분의 버튼입니다 — 다중 선택 토글에는 aria-pressed, 단일 선택에는 일반 상태를 사용하세요 — 메뉴가 필요로 하는 것은 각 칩이 itemId를 갖는다는 것뿐입니다. 즉 칩 상태는 이미 가지고 있는 무엇과도 조합될 수 있습니다: URL 검색 매개변수, 폼 라이브러리, 서버 기반 필터 모델까지. 칩을 삭제하는 것은 항목 제거이고, 사라지는 애니메이션을 주는 것은 items-animation 예제입니다.
모바일: body 스크롤에 관한 한 가지 경고
터치 스크린에서는 바 안에서의 가로 스와이프가 일부 브라우저에서 페이지 전체를 함께 옆으로 끌고 갈 수 있습니다. 이런 현상이 보인다면 prevent-body-scroll 예제에서 이를 막는 touch-action과 오버스크롤 컨테인먼트를 확인하세요 — CSS만으로 해결되며 제스처 라이브러리는 필요 없습니다.
패턴, 최소 구성
칩은 itemId를 가진 토글 버튼이며, 메뉴 API에 대한 ref가 새로 추가된 칩을 화면에 보이도록 스크롤합니다.
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 레지스트리 아이템은 이를 제어 컴포넌트로 제공합니다 — options, selected, onSelectedChange — components/ui/에 Tailwind로 스타일링되어 설치됩니다:
npx shadcn@latest add https://react-horizontal-scrolling-menu.dev/r/chip-bar.json