Staaarter

Horizontal Scroll Snap Cards

A feature section with an eyebrow, heading, and description above a row of icon cards. On mobile and tablet the cards scroll horizontally with CSS scroll-snap; from the lg breakpoint up, the same cards flow into a regular three-column grid.

By Staaarter Team
Feature
Docs
Live preview

Docs

Installation

A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its dependencies and any missing npm packages, and installs them straight into your project.

npx shadcn add https://staaarter.com/r/horizontal-scroll-snap-cards.json

Prefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/feature/feature108.tsx instead.

Usage

The file also exports feature108Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.

import { Feature108, feature108Demo } from "@/components/blocks/feature/feature108";

export default function Page() {
  return <Feature108 {...feature108Demo} />;
}

Props

PropTypeDefaultDescription
eyebrowstringundefinedSmall label above the heading; omitted entirely when unset.
headingReactNodenoneSection heading.
descriptionstringundefinedSupporting copy under the heading.
itemsScrollSnapFeatureCard[]noneCards rendered in order.
classNamestringundefinedExtra classes for the outer section element.

Types

type ScrollSnapFeatureCard = {
  title: string;
  description: string;
  icon: LucideIcon;
};

Behavior notes

  • Server component, no JS: the horizontal scrolling and snapping is pure CSS (`snap-x snap-mandatory` on the track, `snap-center` on each card).
  • Below the lg breakpoint each card is a fixed percentage width (80% on the smallest screens, 45% from sm) so the next card peeks in at the edge, hinting that the row scrolls; from lg the track switches to `lg:grid lg:grid-cols-3` and scroll-snap becomes irrelevant since everything fits without scrolling.
  • Icons are a real prop here (server component, no client-boundary restriction): each card carries its own lucide-react icon component.