Scroll Effects

Section Snap Pin

Section pinning plus snap-scroll choreography — full-height sections snap one by one to fill the viewport, content reveals and exits in order, with side navigation dots.

This is a WebberUI Pro component

The install command below needs a licence to run; without one it returns 401.

How to install Pro components →See the plans →

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add "https://webberui.com/r/section-snap-pin.en.json?t=<install token>"

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

Active edited usageDefault props
<SectionSnapPin/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add "https://webberui.com/r/section-snap-pin.en.json?t=<install token>"

Or, once registries are configured in components.json, install it as @webberui/section-snap-pin.

Usage

SectionSnapPin is itself a vertical snap scroll container, so give it a fixed height (for example h-[80vh] or h-screen). Put several SnapSection elements inside it, and inside each section wrap the elements you want choreographed in SnapReveal.

import {
  SectionSnapPin,
  SnapSection,
  SnapReveal,
} from "@/components/ui/section-snap-pin";

<SectionSnapPin className="h-screen">
  <SnapSection label="Overview" className="bg-neutral-950 text-white">
    <SnapReveal order={0}>
      <span className="text-xs tracking-widest uppercase">01</span>
    </SnapReveal>
    <SnapReveal order={1}>
      <h2 className="text-4xl font-semibold">Snapping sections</h2>
    </SnapReveal>
  </SnapSection>

  <SnapSection label="Choreography" className="bg-indigo-600 text-white">
    <SnapReveal order={0} from="left">
      <h2 className="text-4xl font-semibold">Revealed in order</h2>
    </SnapReveal>
  </SnapSection>
</SectionSnapPin>

Props

SectionSnapPin

PropTypeDefaultDescription
childrenReactNode—One or more SnapSection elements
snap"mandatory" | "proximity""mandatory"Snap strength
indicatorbooleantrueWhether to show the side section navigation dots
indicatorPosition"left" | "right""right"Position of the navigation dots
onActiveChange(index: number) => void—Callback fired when the snapped section changes
aria-labelstring"Section snap scrolling"Accessible label for the scroll area
classNamestring—The outermost container (set the fixed height here)

SnapSection

PropTypeDefaultDescription
childrenReactNode—Section content, usually several SnapReveal elements
labelstring—Section name, used as the navigation dot tooltip and the accessible label
align"start" | "center" | "end""center"Vertical alignment of the content within the section
classNamestring—Additional styling (background, text color, and so on)

SnapReveal

PropTypeDefaultDescription
childrenReactNode—The content to choreograph into view
ordernumber0Reveal order; multiplied by stagger to get the delay
from"up" | "down" | "left" | "right" | "none""up"Direction of the reveal offset
distancenumber24Reveal offset distance (px)
staggernumber0.08Interval between order steps (seconds)
durationnumber0.6Duration of a single unit's animation (seconds)
classNamestring—Additional styling

How it works

  • SectionSnapPin achieves snapping with CSS Scroll Snap (snap-y + snap-mandatory / snap-proximity), leaving scroll performance to the browser's native implementation.
  • Each SnapSection uses an IntersectionObserver (with the scroll container as root) to decide whether it is more than 55% visible and therefore the primary section; that state is passed through context to the inner SnapReveal elements to trigger the reveal, with an exit when it leaves — so scrolling back in choreographs it again.
  • The thin rail beside the navigation dots fills in real time, tracking the container's scroll progress with useScroll.
  • The scroll container's native scrollbar is hidden with styling; snapping and the navigation dots provide the sense of position instead.

Accessibility

  • The scroll container carries role="region", aria-label, and tabIndex, so it can be focused by keyboard and sections switched with ↑ / ↓, PageUp / PageDown, and Home / End.
  • The navigation dots are native <button> elements with an aria-label (taken from the section label) and aria-current; they work by keyboard and show a tooltip.
  • When the user has "reduce motion" enabled at the system level, smooth scrolling becomes an instant jump and SnapReveal renders its content statically with no reveal offset.