npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

scroll-into-view-promise

v1.0.0

Published

Promise-based scrollIntoView. Wraps the native smooth-scroll and resolves when the animation finishes. Tiny. Typed. Zero dependencies.

Readme

🎯 scroll-into-view-promise

Promise-based scrollIntoView. Wraps the native smooth-scroll and resolves when the animation finishes. Zero dependencies.

npm version npm downloads bundle size license TypeScript zero dependencies

Live Demo →


Why

element.scrollIntoView({ behavior: 'smooth' }) works great — but it has no callback. You can't await it. You can't know when it finishes. This is one of the most-searched problems on StackOverflow and has been an open issue in both TC39 and the W3C CSS WG for years.

Existing npm packages like scroll-into-view are old and large. scroll-into-view-if-needed is powerful but solves a different problem. There's no tiny, modern wrapper that simply gives you a Promise around the native API.

scroll-into-view-promise is that wrapper. ~0.6kB gzipped. Zero dependencies. Returns a Promise that resolves when the scroll finishes.


Install

npm install scroll-into-view-promise
# or
yarn add scroll-into-view-promise
# or
pnpm add scroll-into-view-promise

Quick Start

import scrollIntoView from 'scroll-into-view-promise';

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

// Await the scroll — runs code AFTER the animation finishes
await scrollIntoView(section);
console.log('Scroll complete!');

// With options
await scrollIntoView(section, { block: 'center', timeout: 5000 });

Features

  • Promise-basedawait the native smooth scroll, run code when it finishes
  • Zero dependencies — pure TypeScript, no external packages
  • Uses the native API — calls element.scrollIntoView() under the hood, not a custom scroll implementation
  • Scroll-idle detection — resolves by listening for scroll-end on all scrollable ancestors
  • Timeout safety net — never hangs; resolves after a configurable timeout (default 3s)
  • AbortController support — cancel a pending scroll with signal
  • Handles nested scrolling — detects all scrollable parent containers automatically
  • Instant fallback — if behavior: 'instant' or smooth scroll is unsupported, resolves immediately
  • SSR safe — guards DOM access; safe to import in Node/SSR environments
  • ~0.6kB minified + gzipped

API

scrollIntoView(element, options?)

Returns Promise<void> that resolves when the scroll animation finishes.

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

ScrollIntoViewPromiseOptions

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


Examples

Sequential scrolls

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

Focus after scroll

const input = document.getElementById('email-input');
await scrollIntoView(input, { block: 'center' });
input.focus(); // guaranteed to be visible

Cancel with AbortController

const controller = new AbortController();

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

// Cancel after 500ms
setTimeout(() => controller.abort(), 500);

React hook

import { useCallback } from 'react';
import scrollIntoView from 'scroll-into-view-promise';

function useScrollTo() {
  return useCallback(async (selector: string) => {
    const el = document.querySelector(selector);
    if (el) {
      await scrollIntoView(el, { block: 'center' });
    }
  }, []);
}

// Usage
function App() {
  const scrollTo = useScrollTo();

  return (
    <button onClick={() => scrollTo('#pricing').then(() => alert('Done!'))}>
      Jump to Pricing
    </button>
  );
}

Vue composable

import scrollIntoView from 'scroll-into-view-promise';

export function useScrollTo() {
  async function scrollTo(selector: string) {
    const el = document.querySelector(selector);
    if (el) await scrollIntoView(el, { block: 'center' });
  }

  return { scrollTo };
}

CDN (no build step)

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

  document.getElementById('go-btn').addEventListener('click', async () => {
    await scrollIntoView(document.getElementById('target'));
    console.log('Arrived!');
  });
</script>

License

MIT