Package Exports
- scroller-motion
- scroller-motion/dist/index.js
- scroller-motion/dist/index.modern.mjs
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (scroller-motion) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
๐น
scroller-motion
Bringing motion scrolling to React, built upon framer-motion
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
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
: A0
to1
transform ofscrollX|scrollY
, similar to those returned byuseScroll
.x
&y
: A negative representation ofscrollX|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
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