Install the plugin from npm and import it into your bundle:
npm i scrollmirror
import ScrollMirror from "scrollmirror";
Or include the minified production file from a CDN:
<script src="https://unpkg.com/scrollmirror"></script>
Suppose you have the following HTML:
<div class="scrollers">
<div class="scroller">
<!-- some HTML that forces the element to have overflow -->
</div>
<div class="scroller">
<!-- some HTML that forces the element to have overflow. Different length than the previous .scroller -->
</div>
</div>
<style>
.scrollers {
display: grid;
grid-template-columns: 50% 50%;
width: 500px;
}
.scroller {
height: 200px;
overflow: auto; /* this is important! */
}
</style>
This is how you would mirror the scroll position between the two div.scroller
:
import ScrollMirror from "scrollmirror";
/** Mirror all divs that match the class `.scroller` */
new ScrollMirror(document.querySelectorAll(".scroller"));
See also this minimal example on CodePen
💡 To mirror the scroll position from and to the window
, you would have to add one of :root
, html
or body
to the selector:
new ScrollMirror(document.querySelectorAll(":root, .scroller"));
/** or */
new ScrollMirror(document.querySelectorAll("html, .scroller"));
/** or */
new ScrollMirror(document.querySelectorAll("body, .scroller"));
You can pass in a few additional options to ScrollMirror as the second argument:
new ScrollMirror(document.querySelectorAll(".scroller"), options);
The type signature of the options object:
type Options = {
vertical: boolean;
horizontal: boolean;
debug: boolean;
}
Type: boolean
, default: true
. Should the vertical scroll position be mirrored?
Type: boolean
, default: true
. Should the horizontal scroll position be mirrored?
Type: boolean
, default: true
. Should debug messages be printed to the console?
To access ScrollMirror's API, you have to save a reference to the class during instaciation:
const mirror = new ScrollMirror(document.querySelectorAll(".scroller"));
Get the current scroll progress in the form of { x: number, y: number }
, where both x and y are a
number between 0-1
Set the progress and scrolls all mirrored elements. For example:
// for both directions
mirror.progress = { x: 0.2, y: 0.5 };
// or only set one direction
mirror.progress = { y: 0.5 };
// or for both directions at once:
mirror.progress = 0.5;
Get the current progress of an element. The element doesn't need to be one of the mirrored elements
const mirror = new ScrollMirror(document.querySelectorAll(".scroller"));
// ...sometime later:
console.log(mirror.getScrollProgress(document.querySelector(":root")));
There are already a few libraries out there that do the same thing. But all I could find had some limitations (For example, react-scroll-sync needs React, syncscroll doesn't provide an NPM package).
Also, this simple package gave me an excuse to play around with the tooling involved with creating a robust open source npm
package:
- The demo page is generated using Astro and deployed via Netlify
- Browser testing is being done with PlayWright, using the demo site as the source for the test fixtures
- The source code is written in TypeScript