React로 만드는 스토어용 카테고리 레일
카테고리 레일 — 스토어 그리드 위에 놓인, 탭할 수 있는 부서 행 — 은 이커머스에서 트래픽이 가장 높은 스크롤 컨테이너이며, 캐러셀이 아니라 메뉴입니다: 모든 타일이 링크이고, 스냅되는 것은 없으며, 가장자리에 반쯤 걸쳐 보이는 타일이 스크롤을 유도합니다.
레일을 드래그하거나 화살표를 사용해보세요 — 행의 진짜 끝에서 비활성화됩니다.
스토어프론트에서 네이티브 스크롤이 승리하는 이유
스토어프론트 레일은 Lighthouse 점수 1점까지 다투는 페이지에서 접히지 않는 영역(above the fold)에 놓입니다. 캐러셀 엔진은 브라우저가 네이티브로 하는 일을 대신하려고 수십 킬로바이트짜리 제스처 에뮬레이션을 실어 나릅니다. 반면 이 라이브러리는 min+gzip 기준 ≈5.7 kB이며 스크롤을 플랫폼에 맡기므로 하이드레이션 버벅임이 없습니다 — JavaScript가 로드되기 전에도 레일은 스크롤되며, 이는 크롤러가 보는 서버 렌더링 HTML에서도 동작한다는 뜻입니다. 이 페이지 자체가 서버 렌더링의 증거입니다: 위 데모는 JavaScript가 꺼진 상태에서도 스크롤됩니다.
비교 페이지에는 Swiper, Embla, keen-slider, react-slick과 비교한 전체 표가 있습니다.
가시성 추적은 스토어프론트의 기능입니다
항목별 가시성은 상품 진열(merchandising)에 대응시켜 보기 전까지는 구현 디테일처럼 들립니다:
- 지연 이미지 —
useIsVisible이 화면에 보인다고 알릴 때까지 플레이스홀더 타일을 렌더링합니다. - 노출(impression) 분석 — (홈페이지의 히어로 데모에서 실제로 동작하는)
getVisible()은 레일이 렌더링됐다는 사실뿐 아니라 정확히 어떤 카테고리가 보였는지 알려줍니다. - 가장자리를 인식하는 화살표 — add-items 예제처럼 카테고리가 비동기로 로드된 뒤에도 진짜 끝에서 비활성화되거나 숨겨집니다.
디자인 시스템에 맞추기
타일은 여러분의 컴포넌트입니다 — 이미지 카드, 원형, 텍스트 필 등 — 각각이 itemId를 가집니다. 높이와 너비는 여러분의 CSS에서 나오며, 메뉴는 어떤 크기도 강요하지 않습니다. one-item-scroll로 상품 슬라이더처럼 한 번에 한 항목씩 이동하거나, 스크롤 진행 표시기를 보여주거나, RTL 예제로 아랍어와 히브리어 스토어용 RTL을 적용해보세요 — 레일은 설정이 아니라 조합입니다.
패턴, 최소 구성
itemId를 가진 타일과 가시성 훅에서 나오는 화살표 — 레일 전체가 40줄이 채 되지 않습니다.
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