use-scroll-into-view

Scrolls element into view

Import

Usage

use-scroll-into-view handles scroll behavior for any scrollable element. Basic usage works the same way as element.scrollIntoView(). Hook adjusts scrolling animation with respect to the reduced-motion user preference.

Hello there

import { useScrollIntoView } from '@mantine/hooks';
import { Button, Text, Group, Box } from '@mantine/core';

function Demo() {
  const { scrollIntoView, targetRef } = useScrollIntoView<HTMLDivElement>({
    offset: 60,
  });

  return (
    <Group justify="center">
      <Button
        onClick={() =>
          scrollIntoView({
            alignment: 'center',
          })
        }
      >
        Scroll to target
      </Button>
      <Box
        style={{
          width: '100%',
          height: '50vh',
          backgroundColor: 'var(--mantine-color-blue-light)',
        }}
      />
      <Text ref={targetRef}>Hello there</Text>
    </Group>
  );
}

API

The hook is configured with settings object:

  • onScrollFinish – function that will be called after scroll animation
  • easing – custom math easing function
  • duration - duration of scroll animation in milliseconds
  • axis - axis of scroll
  • cancelable - indicator if animation may be interrupted by user scrolling
  • offset - additional distance between the nearest edge and element
  • isList - indicator that prevents content jumping in scrolling lists with multiple targets, for example Select, Carousel

Hook returns an object with:

  • scrollIntoView – function that starts scroll animation
  • cancel – function that stops scroll animation
  • targetRef - ref of target HTML node
  • scrollableRef - ref of scrollable parent HTML element, if not used document element will be used

Returned scrollIntoView function accepts single optional argument alignment - optional target element alignment relatively to parent based on current axis.

scrollIntoView({ alignment: 'center' });

Easing

The hook accept custom easing math function to control the flow of animation. It takes t argument, which is a number between 0 and 1.

Default easing is easeInOutQuad - more info here. You can find other popular examples on easings.net

useScrollIntoView({
  target: someDomElement,
  easing: (t) => (t < 0.5 ? 16 * Math.pow(t, 5) : 1 - Math.pow(-2 * x + 2, 5) / 2), // easeInOutQuint
});

Parent node

Scroll me into view

import { useScrollIntoView } from '@mantine/hooks';
import { Button, Text, Group, Paper, Box } from '@mantine/core';

function Demo() {
  const { scrollIntoView, targetRef, scrollableRef } = useScrollIntoView<
    HTMLDivElement,
    HTMLDivElement
  >();

  return (
    <Group justify="center">
      <Paper ref={scrollableRef} h={300} style={{ overflowY: 'scroll', flex: 1 }}>
        <Box pt={260} pb={450}>
          <Paper
            ref={targetRef}
            p="xl"
            style={{
              backgroundColor: 'var(--mantine-color-blue-light)',
              width: '100%',
            }}
          >
            <Text>Scroll me into view</Text>
          </Paper>
        </Box>
      </Paper>
      <Button onClick={() => scrollIntoView()}>Scroll to target</Button>
    </Group>
  );
}

Scroll X axis

Scroll me into view

import { useScrollIntoView } from '@mantine/hooks';
import { Button, Text, Group, Paper, Box } from '@mantine/core';

function Demo() {
  const { scrollIntoView, targetRef, scrollableRef } = useScrollIntoView<
    HTMLDivElement,
    HTMLDivElement
  >({ axis: 'x' });

  return (
    <Group justify="center">
      <Paper ref={scrollableRef} h={150} w={300} style={{ overflowX: 'scroll' }}>
        <Box pl={260} pr={450}>
          <Paper
            ref={targetRef}
            p="md"
            style={{
              backgroundColor: 'var(--mantine-color-blue-light)',
              width: 'max-content',
            }}
          >
            <Text>Scroll me into view</Text>
          </Paper>
        </Box>
      </Paper>
      <Button onClick={() => scrollIntoView()}>Scroll to target</Button>
    </Group>
  );
}

Definition

function useScrollIntoView<
  Target extends HTMLElement,
  Parent extends HTMLElement | null = null
>({
  onScrollFinish?: () => void;
  duration?: number;
  axis?: 'x' | 'y';
  easing?: (t: number) => number;
  offset?: number;
  cancelable?: boolean;
  isList?: boolean;
}): {
  targetRef: MutableRefObject<Target>;
  scrollableRef: MutableRefObject<Parent>;
  scrollIntoView: ({
    alignment?: 'start' | 'end' | 'center';
  }) => void;
  cancel: () => void;
};