Search code examples
next.jsscrollroutersmoothing

How can I activate Smooth scroll in next.js


I want to do smooth scroll with router hash but next js don't understand it. I use this function

export const scrollTo = (id: string) => {
    const element = document.getElementById(id);

    if (element) {
        window.scrollTo({
            top: element.getBoundingClientRect().top + window.scrollY,
            left: 0,
            behavior: 'smooth',
        });
    }
};

But when I use it I need to disable router push,

import Link from 'next/link';
import React from 'react';
import _ from 'lodash';
import useAppRouter from '../../../hooks/useAppRouter';

interface INavigation {
    links: string[];
}

const Navigation: React.FC<INavigation> = ({ links }) => {
    const router = useAppRouter();

    const handleCLick = (e,link) =>{
        e.preventDefault();
        scrollTo(link)
    }

    return (
        <section className="stories-navigation">
            <ul>
                {links.map((link: string) => (
                    <Link href={`#${link}`} key={link}>
                        <li>
                            <a onClick={e => handleCLick(e, link)} className={router.hash === link ? 'active-link' : ''}>
                                {_.capitalize(link)}
                            </a>
                        </li>
                    </Link>
                ))}
            </ul>
        </section>
    );
};

export default Navigation;

But I also need to show this #hashlink, but when I use and next js don't understand scrollTo function and scroll imadiatly without smooth


Solution

  • Here helper callback functions for next/router events. It works globally for next js.

    export const smoothScroll = () => {
      const html = document.querySelector('html');
      if (html) {
        html.style.scrollBehavior = 'smooth';
      }
    };
    export const removeSmoothScroll = () => {
        const html = document.querySelector('html');
       if (html) {
           setTimeout(() => {
               html.style.scrollBehavior = 'unset';
           }, 0);
       }
    };
    

    And use this events above App component

    Router.events.on('hashChangeStart', smoothScroll);
    Router.events.on('hashChangeComplete', removeSmoothScroll);