Skip to content

Vanilla JavaScript scroll restoration for overflowing elements and the window using history.state ♻️

License

Notifications You must be signed in to change notification settings

hirasso/restore-scroll

Repository files navigation

@hirasso/restore-scroll

e2e test status unit test status license

Vanilla JavaScript scroll restoration for overflowing elements and the window using history.state ♻️

Demo

restore-scroll.js.org

Installation

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>

Usage

/**
 * 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);

Arguments

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,
  }
}

Options

debug

Type: boolean, default: false. Log debug info to the console

Events

Listening to events can be done in two ways:

Option 1: Attach listeners declaratively

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),
  },
});

Option 2: Attach listeners to the element directly

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();
      }
    },
  },
});

Motivation

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.

About

Vanilla JavaScript scroll restoration for overflowing elements and the window using history.state ♻️

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Contributors 2

  •  
  •