P
L
zero dependencies
rAF-based
TypeScript
a11y ready

npm package

react-parallax

Scroll and pointer parallax for React. One container, unlimited layers. Move your cursor.

npm i @iampoul/react-parallaxGitHub →
v0.2.0|MIT|React ≥18

Get started

Installation

npm install @iampoul/react-parallax
  • Zero dependenciesOnly a React peer dependency required
  • PerformantSingle rAF loop — layers update via refs, no re-renders
  • AccessibleAuto-pauses for prefers-reduced-motion
  • FlexibleScroll, pointer, or both. Per-layer speed, rotate, scale, fade, blur
  • TypeScriptFull type definitions included
scene.tsx
import { Parallax, ParallaxLayer } from "@iampoul/react-parallax"

export function Scene() {
  return (
    <Parallax mode="both" intensity={1} smoothing={0.12}>
      {/* Background — moves slower, blurs at scroll edges */}
      <ParallaxLayer speed={0.5} pointerStrength={20} blur={4}>
        <img src="/bg.png" alt="" />
      </ParallaxLayer>

      {/* Foreground — moves faster, always slightly soft */}
      <ParallaxLayer speed={-0.3} pointerStrength={40} blurBase={2} zIndex={1}>
        <img src="/fg.png" alt="" />
      </ParallaxLayer>
    </Parallax>
  )
}

Examples

Demos

Scroll depth

Layers with different speed values create depth as you scroll. Positive values recede into the background, negative values come forward.

scroll to see depth
<Parallax mode="scroll" intensity={1} smoothing={0.1}>
  {/* Slowest — furthest away */}
  <ParallaxLayer speed={0.7} scrollRange={80}></ParallaxLayer>
  {/* Mid distance */}
  <ParallaxLayer speed={0.35} scrollRange={80}></ParallaxLayer>
  {/* Fastest — closest */}
  <ParallaxLayer speed={-0.4} scrollRange={80}></ParallaxLayer>
</Parallax>

Pointer tilt

pointerStrength controls how far each layer shifts in response to the cursor. Higher values create more dramatic parallax.

move cursor here
<Parallax mode="pointer" intensity={1.2} smoothing={0.07}>
  <ParallaxLayer pointerStrength={12}></ParallaxLayer>
  <ParallaxLayer pointerStrength={28}></ParallaxLayer>
  <ParallaxLayer pointerStrength={50}></ParallaxLayer>
  <ParallaxLayer pointerStrength={80}></ParallaxLayer>
</Parallax>

Rotate, scale & fade

Combine rotate, scale, and fade on layers for richer scroll transitions.

scroll to see transforms
<Parallax mode="scroll" intensity={1} smoothing={0.1}>
  <ParallaxLayer speed={0.2} rotate={120} scrollRange={100} />
  <ParallaxLayer speed={-0.3} rotate={-80} scale={0.3} scrollRange={100} />
  <ParallaxLayer speed={0.5} fade={0.2} scrollRange={100} />
</Parallax>

Blur depth-of-fieldv0.2.0

The blur prop applies a dynamic blur() CSS filter — sharp at scroll center, soft toward the edges. Like a camera pulling focus.

scroll to pull focus
<Parallax mode="scroll" intensity={1} smoothing={0.1}>
  {/* Far — blurs out at scroll edges */}
  <ParallaxLayer speed={0.6} blur={10} scrollRange={90} />
  {/* Mid — subtle blur */}
  <ParallaxLayer speed={0.25} blur={5} scrollRange={90} />
  {/* Near — always sharp */}
  <ParallaxLayer speed={-0.3} blur={0} scrollRange={90} />
</Parallax>

Always-soft backgroundv0.2.0

blurBase applies a constant blur at all scroll positions — perfect for soft atmospheric backgrounds. Composes with blur: total = blurBase + |scroll| × blur.

move cursor & scroll
<Parallax mode="both" intensity={1} smoothing={0.09}>
  {/* Always blurred — constant soft atmosphere */}
  <ParallaxLayer speed={0.5} blurBase={5} scrollRange={80} />
  {/* Blurred + gets softer toward edges */}
  <ParallaxLayer speed={0.2} blurBase={3} blur={4} scrollRange={80} />
  {/* Sharp focal point */}
  <ParallaxLayer speed={-0.15} scrollRange={80} />
</Parallax>

Live playground

Tweak the <Parallax> container props in real time. The code block reflects your current settings.

<Parallax> props

mode
disabled
<Parallax
  mode="both"
  intensity={1.0}
  smoothing={0.10}
  disabled={false}
>

API Reference

Props

<Parallax>

The container element that tracks scroll and pointer movement and broadcasts it to all child layers via a ref-based subscription — no re-renders.

proptypedefaultdescription
mode"scroll" | "pointer" | "both""both"Which inputs drive the parallax effect
intensitynumber1Global movement multiplier — 0.5 subtle, 2 dramatic
smoothingnumber0.12Easing factor — lower is floatier, 1 is instant
disabledbooleanfalsePause all motion. Auto-enabled for prefers-reduced-motion
asElementType"div"HTML element to render as the container
classNamestringCSS class for the container element
styleCSSPropertiesInline styles for the container element

<ParallaxLayer>

A single layer inside a container. Drop in as many as needed. Each layer independently controls its depth, motion axis, rotation, scale, and fade.

proptypedefaultdescription
speednumber0.3Depth factor — 0 locked, >0 slower/background, <0 faster/foreground
pointerStrengthnumber0Pixels of travel from pointer movement
scrollRangenumber120Max pixels of scroll travel
axis"x" | "y" | "both""y"Which axis scroll parallax applies to
rotatenumber0Degrees of rotation applied across the scroll range
scalenumber0Extra scale applied at scroll edges (0.2 = +20%)
fadenumber1Opacity at scroll edges — 1 means no fade
blurnumber0Max blur in px at scroll edges, 0px at center — creates a depth-of-field focus effect
blurBasenumber0Constant blur in px always applied — for layers that should always appear out of focus. Composes with blur
zIndexnumber0Stacking order for the layer
asElementType"div"HTML element to render as the layer
classNamestringCSS class for the layer element
styleCSSPropertiesInline styles for the layer element

useParallax()

Access the parallax context from custom components inside a container.

const { intensity, disabled, mode, subscribe, getState } = useParallax()