Horizontal Scroll
A free horizontal scroll section that glides panels sideways as you scroll.
- Automated axe check
- Reduced-motion tested
- SSR build verified
- GSAP
- 2 runtime packages
Horizontal Scroll is a free scroll section for Next.js and React that pins to the viewport and slides between two and six panels sideways as the page scrolls, driven by a single GSAP ScrollTrigger scrub and styled with Tailwind. You pass your panels as plain children, one per direct child, and the component builds the flex row track, the pinned tween and the reduced motion fallback for you.
The scrub follows native scrolling and never blocks it, so wheel, keyboard and touch all carry you straight through and past the section, and the pin spacer reserves the scroll distance so pinning causes no layout shift. With prefers-reduced-motion enabled, or with JavaScript unavailable, no ScrollTrigger is created at all: the panels render as a static vertical stack, fully visible in order.
Scene 01
The page turns sideways
As the section reaches the top of the viewport it pins in place, and your vertical scroll becomes horizontal travel. Each viewport of scrolling glides one full panel across the screen.
Scene 02
Every panel gets the stage
The track is tied directly to the scrub, so it moves exactly as fast as you scroll. Slow down and the panels drift; stop and the story holds mid-glide until you move again.
Scene 03
Straight through to the end
Nothing is trapped. Wheel, keyboard or touch carries you past the final panel and the pin releases, and with reduced motion the three scenes simply stack in order.
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/scroll-horizontalUsage
import { ScrollHorizontal } from "@/components/scroll-horizontal";
export default function Page() {
return (
<ScrollHorizontal>
<div>
<h2>Scene one</h2>
<p>The section pins and scroll turns sideways.</p>
</div>
<div>
<h2>Scene two</h2>
<p>Each panel glides across, tied to the scrub.</p>
</div>
<div>
<h2>Scene three</h2>
<p>Scroll on and the pin releases.</p>
</div>
</ScrollHorizontal>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | required | Panel content. Pass 2 to 6 direct children; each direct child is rendered inside its own [data-panel] wrapper as one panel, in DOM order. |
| className | string | undefined | Additional classes merged onto the section root. |
Customisation
Horizontal Scroll declares no tokens of its own: the section and each panel surface use the semantic background token, and everything inside a panel is your own markup, styled however you like. To retheme the section, restyle your panel content directly or override the semantic tokens it consumes from :root or any ancestor:
:root {
--background: var(--color-neutral-900);
--foreground: var(--color-neutral-50);
}Frequently asked questions
- Is Horizontal Scroll free for commercial use?
- Yes. Horizontal Scroll is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Does Horizontal Scroll trap scrolling or hurt accessibility?
- No. The sideways travel is scrubbed from native vertical scroll and never intercepts it, so mouse wheel, trackpad, touch and keyboard keys such as arrows, space and PageDown all move through and past the section uninterrupted, with no snap points. The pin spacer reserves the full scroll distance up front, so pinning causes no layout shift, and the tween animates a single transform on the track. Every panel stays visible and Tab reachable in both modes, focusing content in an offscreen panel scrolls it into view natively, and with reduced motion enabled the panels render as a static vertical stack with no ScrollTrigger created at all.
- How do I change the number of panels or their content?
- Pass between two and six direct children to the component; each direct child becomes one panel in DOM order, and the scroll distance scales with the panel count automatically. Panels are plain containers, so headings, text, images and layout inside each one are entirely your own markup and Tailwind classes, and heading levels stay under your control.