Zero dependencies · TypeScript · ~0.6kB gzip

await your
scrollIntoView

The native scrollIntoView({ behavior: 'smooth' }) has no callback. You can't know when it finishes. This tiny wrapper returns a Promise that resolves when the scroll is done.

✦ Try the live demo
Promise-based Uses native API AbortController support SSR safe ~0.6kB gzip
Why scroll-into-view-promise

Everything you need, nothing you don't

Promise when done

await scrollIntoView(el) — run code after the scroll animation finishes. No guessing with setTimeout.

🌐

Native under the hood

Calls the real element.scrollIntoView(). Not a custom scroll implementation. You get native browser behavior.

🔍

Scroll-idle detection

Listens for scroll events on all scrollable ancestors. Resolves when scrolling stops — works with nested containers too.

⏱️

Timeout safety net

Configurable timeout (default 3s) ensures the Promise always resolves. Never hangs your async flow.

🚫

Zero dependencies

Pure TypeScript. ~0.6kB gzipped. No bloat, no transitive deps, no supply chain risk.

AbortController

Pass an AbortSignal to cancel a pending scroll. The Promise rejects with an AbortError.

Interactive Demo

Try it right here

Click a section — watch the Promise resolve

Each button calls await scrollIntoView(section) and logs when the Promise resolves.

Section 01
Introduction
The native scrollIntoView API is great — but it fires and forgets. You have no way to know when the animation completes.
Section 02
The Problem
Developers use arbitrary setTimeout delays as workarounds. These break on slow devices, different scroll distances, and reduced-motion preferences.
Section 03
The Solution
scroll-into-view-promise wraps the native API and returns a Promise. It detects when scrolling stops by listening for scroll-idle on all scrollable parents.
Section 04
Use Cases
Sequential scroll tours, focus-after-scroll, form validation scroll-then-highlight, table of contents with active state, and more.
Section 05
Tiny Footprint
~0.6kB gzipped. Zero dependencies. ESM + CJS + TypeScript types. Works everywhere — React, Vue, Svelte, vanilla JS.
Click a section button above to start...
Get Started

Install in 30 seconds

npm install scroll-into-view-promise
yarn add scroll-into-view-promise
pnpm add scroll-into-view-promise
<script type="module">
  import scrollIntoView from 'https://esm.sh/scroll-into-view-promise';
</script>
import scrollIntoView from 'scroll-into-view-promise';

const el = document.getElementById('pricing');

await scrollIntoView(el);
console.log('Scroll complete!');

// With options
await scrollIntoView(el, { block: 'center' });
import scrollIntoView from 'scroll-into-view-promise';

async function walkthrough() {
  await scrollIntoView(document.getElementById('step-1'));
  showTooltip('step-1');

  await scrollIntoView(document.getElementById('step-2'));
  showTooltip('step-2');

  await scrollIntoView(document.getElementById('step-3'));
  showTooltip('step-3');
}
import scrollIntoView from 'scroll-into-view-promise';

const input = document.getElementById('email-input');

// Scroll, THEN focus — guaranteed visible
await scrollIntoView(input, { block: 'center' });
input.focus();
import scrollIntoView from 'scroll-into-view-promise';

const ctrl = new AbortController();

scrollIntoView(target, { signal: ctrl.signal })
  .catch(err => {
    if (err.name === 'AbortError')
      console.log('Scroll cancelled');
  });

// Cancel after 500ms
setTimeout(() => ctrl.abort(), 500);
API Reference

Function signature

Param Type Description
element Element The DOM element to scroll into view.
options ScrollIntoViewPromiseOptions Optional configuration (see below).

Options

Option Type Default Description
behavior 'smooth' | 'instant' | 'auto' 'smooth' Scroll behavior, passed to the native API.
block 'start' | 'center' | 'end' | 'nearest' 'start' Vertical alignment of the element.
inline 'start' | 'center' | 'end' | 'nearest' 'nearest' Horizontal alignment of the element.
timeout number 3000 Max wait time (ms) before resolving anyway.
signal AbortSignal Abort signal to cancel and reject the Promise.