Comment faire un composant ScrollToTop avec React

Comment faire un composant ScrollToTop avec React

React Typescript Tailwind

Introduction

Dans cet article nous allons découvrir comment réaliser un composant ScrollToTop, afin de remonter en haut d’une page Web, de manière smooth.

Pour ce faire, nous utiliserons la méthode window.scrollTo() supportée dans la plupart des navigateurs.

La méthode scrollTo accepte en entrée un objet contenant des coordonnées left & right, ainsi qu’un champ behavior définissant le comportement du scroll :

window.scrollTo({top: 0, left: 0, behavior: 'smooth'}); 

Le composant IconArrowTop

Commençons par créer un composant IconArrowTop qui hébergera un icône pour la flêche du ScrollToTop :

// src/components/icons/IconArrowTop.tsx

impor { FunctionComponent } from "react";

const IconArrowTop: FunctionComponent = () => {
  return (
    <svg
      className="h-8 w-8"
      xmlns="http://www.w3.org/2000/svg"
      fill="none"
      viewBox="0 0 26 26"
      stroke="currentColor"
      strokeWidth="2"
    >
      <path strokeLinecap="round" strokeLinejoin="round" d="M5 15l7-7 7 7" />
    </svg>
  );
};

export default IconArrowTop;

Rien de bien particulier ici, il s’agit d’un functional component qui renvoie un svg. Nous utilisons également les classes Tailwind w-8 et h-8 pour fixer une taille par défaut, à l’icône.

Le composant ScrollToTop

Nous allons par la suite, créer notre composant ScrollToTop, pour l’instant il renverra uniquement le composant IconArrowTop :

// src/components/ui/ScrollToTop.tsx

import { FunctionComponent } from "react";
import ArrowTopIcon from "../icons/IconArrowTop";

const ScrollToTop: FunctionComponent = () => {
  return (<ArrowTopIcon />);
};

export default ScrollToTop; 

Passons ensuite, à la partie plus intéressante, nous souhaitons cacher le ScrollToTop à partir d’un certain offset de l’axe Y. Cela permettra à l’utilisateur de voir le composant à partir du moment ou il aura assez scrollé vers le bas.

// src/components/ui/ScrollToTop.tsx

import { FunctionComponent, useEffect, useState } from "react";
import ArrowTopIcon from "../icons/IconArrowTop";

const minYOffset = 400;

const ScrollToTop: FunctionComponent = () => {
  const [scrollY, setScrollY] = useState(0);

  const checkScrollTop = () => setScrollY(window.pageYOffset);

  return (
    <div
      className={`${
        scrollY > minYOffset ? "flex" : "hidden"
      } z-20 fixed bottom-6 right-6 md:bottom-20 md:right-20 cursor-pointer animate-bounce bg-white p-2 w-16 h-16 border border-gray-200 text-secondary shadow-lg rounded-full items-center justify-center`}
    >
      <ArrowTopIcon />
    </div>
  );
};

export default ScrollToTop;

La méthode checkScrollTop permettra de setter la valeur courante du scroll.

Vous remarquerez que nous avons aussi ajouter une condition sur les classes css Tailwind (flex / hidden) du composant afin d’afficher ou cacher l’élément selon la position du scroll de l’utilisateur. Si le scroll est supérieur à 400px, l’élément apparaîtra.

Il ne nous reste plus qu’à détecter la position du scroll de l’utilisateur à l’aide du hook useEffect et d’utiliser la méthode window.scrollTo() fournie par le navigateur :

// src/components/ui/ScrollToTop.tsx

import { FunctionComponent, useCallback, useEffect, useState } from "react";
import ArrowTopIcon from "../icons/IconArrowTop";

const minYOffset = 400;

const ScrollToTop: FunctionComponent = () => {
  const [scrollY, setScrollY] = useState(0);

  const checkScrollTop = useCallback(
    () => setScrollY(window.pageYOffset),
    [setScrollY]
  );

  useEffect(() => {
    window.addEventListener("scroll", checkScrollTop);
    return () => window.removeEventListener("scroll", checkScrollTop);
  }, [checkScrollTop]);

  const scrollTop = () => window.scrollTo({ top: 0, behavior: "smooth" });

  return (
    <div
      className={`${
        scrollY > minYOffset ? "flex" : "hidden"
      } z-20 fixed bottom-6 right-6 md:bottom-20 md:right-20 cursor-pointer animate-bounce bg-white p-2 w-16 h-16 border border-gray-200 text-secondary shadow-lg rounded-full items-center justify-center`}
      onClick={scrollTop}
    >
      <ArrowTopIcon />
    </div>
  );
};

export default ScrollToTop;

Nous avons également utiliser le hook useCallback afin de s’assurer que la fonction checkScrollToTop garde la même référence et ne re-déclenche pas le code situé dans le hook useEffect.

Une fonction de nettoyage est également retournée dans l’appel du useEffect, cela permet de proprement retirer le listener dans le cas où le composant est détruit ou est ré-évalué après un rendering.

Pour finir, l’évènement onClick a été utilisé sur la div parente du ScrollToTop. La méthode scrollTop étant connectée à ce listener.