Ponyfill

This package ponyfills new features in the Element.scrollIntoView API. Including features in the non-standard Element.scrollIntoViewIfNeeded API, that the CSS working group is proposing to add to scrollIntoVIew as another option: scrollMode: "if-needed".

Minimal

The core package scroll-into-view-if-needed is unapologetically small and dependency-free. That is why behavior: "smooth" is only ponyfilled if you use the add-on package smooth-scroll-into-view-if-needed. You don't need the add-on if native smooth scrolling is enough.

Customizable

A couple of options not in the spec by the CSS working group helps customize scrolling to your needs. Avoid scrolling unwanted parent elements by using the boundary: Element option. Pass a function to behavior to customize exactly how elements are scrolled when smooth isn't enough.

Scrolling if needed

When deciding if scrolling is needed the visibility of the target element is checked. If it's less than 100% it will be scrolled.

By default the browser controls the scrolling when behavior: 'smooth' (unless you opt in to the ponyfill). Note there's browser differences with native smooth scrolling, like Chrome vs FireFox in this CodePen.

Behavior
Scroll mode
import scrollIntoView from 'smooth-scroll-into-view-if-needed';

scrollIntoView(node, {
  behavior: 'smooth',
  scrollMode: 'if-needed',
});
Scroll to 
A
B
C
D
E
F
G

Scroll alignment

The position options for both block and inline are supported. Mix and match to your heart's content.

Usually block aligns vertically, while inline aligns horizontally. It depends on the writing-mode.

Block
Inline
import scrollIntoView from 'scroll-into-view-if-needed';

scrollIntoView(node, {
  behavior: 'smooth',
  block: 'center',
  inline: 'center',
});
Scroll to 
1
2
3
4
5
6
7
8
9

Limit propagation

Boundaries are good, that's what people keep saying. If you want some elements to scroll into view, but not all of the parents then boundary is the answer.

Keep in mind this is a non-standard feature not in any spec.

Block
import scrollIntoView from 'scroll-into-view-if-needed';

scrollIntoView(node, {
  behavior: 'smooth',
  block: 'end',
  boundary: document.getElementById('example-boundary'),
});
Scroll to 
😁
🤯
😅
🤔
🤩
🤨
😲

Custom transition: popmotion example

If you want a different easing, duration or another creative direction you can pass a function to behavior.

Just like boundary this is not in the spec.

Inline
import scrollIntoView from 'scroll-into-view-if-needed';
import Styler from 'stylefire';
import { animate } from 'popmotion';

scrollIntoView(node, {
  behavior: (instructions) => {
    const [{ el, left }] = instructions;
    const styler = Styler(el);

    animate({
      from: el.scrollLeft,
      to: left,
      type: 'spring',
      onUpdate: (left) => styler.set('scrollLeft', left),
    });
  },
  inline: 'center',
});
Scroll to 
🌎
🌍
🌏