Vanilla JavaScript scroll restoration for overflowing elements and the window using history.state
♻️
Install and import into your bundle
npm i @hirasso/restore-scroll
import { restoreScroll } from "@hirasso/restore-scroll";
Or import the module directly from a CDN for quick tests:
<script type="module">
import { restoreScroll } from "https://unpkg.com/@hirasso/restore-scroll@0";
</script>
/**
* Track and restore the scroll positions of all overflowing divs,
* identified by tailwind classes in this case:
*/
document
.querySelectorAll(".overflow-y-auto,.overflow-x-auto,.overflow-auto")
.forEach((el) => restoreScroll(el));
💡 If history.scrollRestoration
is set to manual
, you might want to restore the window scroll position as well:
window.history.scrollRestoration = "manual";
restoreScroll(window);
The first argument target
accepts either an element or the Window
:
export type Target = Element | Window;
The second argument options
accepts this:
type Options = {
debug?: boolean;
events?: {
store?: (el: Element, event: CustomEvent<position: ScrollPosition>) => void,
restore?: (el: Element, event: CustomEvent<position: ScrollPosition>) => void,
}
}
Type: boolean
, default: false
. Log debug info to the console
Listening to events can be done in two ways:
import { restoreScroll } from "@hirasso/restore-scroll";
restoreScroll(el, {
events: {
store: (el, event) => console.log("stored", el, event),
restore: (el, event) => console.log("restored", el, event),
},
});
DOM events are prefixed with restore-scroll:
:
import { restoreScroll } from "@hirasso/restore-scroll";
const el = document.querySelector("#foo");
el.addEventListener("restore-scroll:restore", (e) => {
const event = e as CustomEvent<{ position: ScrollPosition }>;
/** The position is available in event.detail.position */
console.log(event.detail.position);
});
restoreScroll(el);
event.preventDefault
works as expected:
restoreScroll(el, {
events: {
restore: (el, event) => {
if (someCondition()) {
/** The element won't be restored */
event.preventDefault();
}
},
},
});
There already are other solutions for storing and restoring the scroll position. But all I could find was either archived by their owner, had a dependency (React in most cases) or was using sessionStorage
for storing the scroll positions, which is not ideal (with sessionStorage
, one URL can only store one scroll state, ever). Hence, this new little package.