Skip to content

breadadams/scroller-motion

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ›น
scroller-motion

NPM Package Version Project Storybook Tests Workflow Status Formatting Workflow Status

Bringing motion scrolling to React, built upon framer-motion


  1. Installation
  2. Usage
  3. Props
  4. useScrollerMotion
  5. Listeners
  6. Recipes
  7. About
  8. Contributing
  9. License

Installation

To begin you'll want to install scroller-motion as well as the peer dependencies:

npm install scroller-motion framer-motion react

# or

yarn add scroller-motion framer-motion react

Note: Due to the use of hooks the minimum required version of React is 16.8

Usage

Implementing scroller-motion couldn't be easier, simply wrap your page with the <ScrollerMotion> component. For example in a Next.js app this might look like the following:

/* pages/index.jsx */

import { ScrollerMotion } from 'scroller-motion'

export default () => (
  <ScrollerMotion>
    <MyComponent />
  </ScrollerMotion>
)

Most modern browsers implement an inertia bounce effect to the window while scrolling (upon reaching the start/end). This can cause unwanted visual effects, such as flickering, when using scroller-motion.

To fix this, you can disable overscroll-behavior in your project with the following CSS:

/* style.css */

html,
body {
  overscroll-behavior: none;
}

Props

All props are optional.

disabled

Type boolean
Default false
Description Completly disables and unmounts the ScrollerMotion component. Any children will be rendered through a React <Fragment> in this case (thus falling back to native scrolling).

scale

Type number
Default 1
Demo View demo
Description Extends the scrollable length of the page, giving a "slow scroll" experience. For example if the page content is 1400px in height, <ScrollerMotion scale={1.5} /> would result in a scrollable length of 2100px (height * scale).

The lowest this value can be is 1, anything lower will be disregarded and 1 will be used in its place.

spring

Type SpringOptions
Default { mass: 1.25, stiffness: 200, damping: 50 }
Demo View demo
Description The main configuration object for the scroll's spring transform, basically the 2nd parameter to framer-motion's useSpring.

You can disable the spring scroll by passing a falsy value to this prop, for example: <ScollerMotion spring={null} />.

useScrollerMotion hook

View demo

This hook allows you to consume the internal MotionValue values, returning an object of the following type:

{
  scrollX: MotionValue,
  scrollXProgress: MotionValue,
  scrollY: MotionValue,
  scrollYProgress: MotionValue,
  x: MotionValue,
  y: MotionValue
}
  • scrollX & scrollY: The current scroll position.
  • scrollXProgress & scrollYProgress: A 0 to 1 transform of scrollX|scrollY, similar to those returned by useScroll.
  • x & y: A negative representation of scrollX|scrollY.

It must be used within a <ScrollerMotion />, to read the values in the parent component see Motion Listeners.

โ„น๏ธ For accessing native scroll values (without spring motion or scale calculation) we suggest using framer-motion's useScroll.

import { ScrollerMotion, useScrollerMotion } from 'scroller-motion'
import { motion } from 'framer-motion'

const MyComponent = () => {
  const { x, y } = useScrollerMotion()

  return <motion.div style={{ x, y }}>Hello world</motion.div>
}

export default () => (
  <ScrollerMotion>
    <MyComponent />
  </ScrollerMotion>
)

Motion Listeners

View demo

Another approach if you need to read/use the internal MotionValue values is via the ref prop on <ScrollerMotion />. The type of the ref is the same as the object returned from useScrollerMotion.

For example, if we want to use the y-axis scroll position:

import { useEffect, useRef } from 'react'
import { useMotionValue } from 'framer-motion'
import { ScrollerMotion, ScrollerMotionRef } from 'scroller-motion'

export default () => {
  const scrollerMotion = useRef<ScrollerMotionRef>()
  const scrollY = useMotionValue(0)

  useEffect(() => {
    const unsubscribe = scrollerMotion.current.scrollY.onChange((v) =>
      scrollY.set(v)
    )

    return () => unsubscribe()
  }, [scrollY])

  return (
    <ScrollerMotion ref={scrollerMotion}>
      <MyComponent scrollPosition={scrollY} />
    </ScrollerMotion>
  )
}

โ„น๏ธ For accessing native scroll values (without spring motion or scale calculation) we suggest using framer-motion's useScroll.

Recipes

  • Hash anchor scroll: Scroll the window to a DOM element when clicking a #hash anchor.
  • Horizontal scroll: Convert vertical mousewheel events to horizontal window scroll.
  • Tab scroll: Scroll the window to a DOM element when pressing the Tab key (useful for a11y purposes).

About

Scroller-motion was born from the need for motion/smooth scrolling in a couple of React projects. Given the fact that we were already using the beloved framer-motion for the rest of the animations & transitions, we decided to try it out for page scrolling too - and the results were impressive! Time for an emoji list:

  • ๐Ÿ€ Configurable motion via the spring prop
  • ๐Ÿ–ฑ "Slow scroll" via the scale prop
  • ๐Ÿ“ก Subscribe to the scroll values with useScrollerMotion
  • โš™๏ธ SSR compatible
  • ๐Ÿค– Fully typed w/ TypeScript
  • ๐Ÿช Built around React hooks
  • โš–๏ธ Only ~2kb gzipped

Contributing

These are the current scripts available for development:

# Start Storybook
npm run start

# Build dist files
npm run build

# Build static Storybook
npm run build:storybook

# Apply Prettier formatting
npm run prettier:format

# Check Prettier formatting
npm run prettier:check

# Run tests
npm run test

License

Released under the MIT License.
Authored and maintained by Brad Adams with help from contributors.

breadadams.com ยท GitHub @breadadams ยท Twitter @breadadams