9

How can I set the scroll effect to smooth (globally) in Next.js? I tried to do it on the global css, but it deactivates the scroll-to-top that Next js already has.

I tried this solution that i found on internet too, but it didn't worked either.

 componentDidMount() {
 Router.events.on('routeChangeComplete', () => {
    window.scroll({
       top: 0,
       left: 0,
       behavior: 'smooth'
    });
 });

}

Mechanic
  • 5,015
  • 4
  • 15
  • 38
Manuel Nelson
  • 137
  • 1
  • 1
  • 8

11 Answers11

40

Add scroll-behavior:smooth in html or body. Then adding in

<Link href="#someid" scroll={false}>

works

Shubham Gaikwad
  • 553
  • 5
  • 4
  • 2
    Thanks buddy. I was facing similar issue and didn't knew that there is a scroll props to nextjs Link. It was helpful. – Milan Patel Apr 01 '23 at 11:15
12

Just put style={{scrollBehavior:'smooth'} in the tag Html in '_document.tsx' file.

Like :

class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const initialProps = await Document.getInitialProps(ctx);
    return { ...initialProps };
  }

  render() {
    return (
      <Html className='scroll-smooth' style={{scrollBehavior:'smooth'}}>
        <Head>
          <link rel='icon' href='/favicon.ico' />
          <meta
            name='description'
            content='A place to find a great film to watch'
          />
        </Head>
        <body className='bg-gray-50 screen'>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}
2

If you're using Class Component, you may copy and paste the following code:

import React, { Component } from 'react';

export default class ScrollToTopButton extends Component {
  // this is function that will scroll to the top of the page when the button is clicked
  scrollToTop = () => {
    window.scrollTo({
      top: 0,
      behavior: 'smooth',
    });
  };

  render() {
    return (
      <>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        <div> textInComponent </div>
        {/* This is the button that will go up */}
        <button onClick={() => this.scrollToTop()}> textInComponent </button>
      </>
    );
  }
}

Alternatively, if you're implementing a function component

import React, { Component } from 'react';

function ScrollToTopButton() {
  // this is function that will scroll to the top of the page when the button is clicked
  const scrollToTop = () => {
    window.scrollTo({
      top: 0,
      behavior: 'smooth',
    });
  };

  return (
    <>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      <div> textInComponent </div>
      {/* This is the button that will go up */}
      <button onClick={() => scrollToTop()}> textInComponent </button>
    </>
  );
}

export default ScrollToTopButton;

I'm not sure how to describe this code, but it works on my end; I hope it helps!

Atif Khan
  • 206
  • 1
  • 10
1

Go to your global or main css folder and write:

html{scroll-behavior: smooth;}

or, if you are using Tailwind, go into your _document.js file and apply this:

import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
  return (
    <Html lang="en" className='scroll-smooth'>
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

If you want smooth scrolling between links on the same page, do something like this where you are manipulating the scroll property on the next/link component:

<Link href="/#skills" scroll={false}>
    <li className="ml-10 text-sm uppercase hover:border-b">Skills</li>
</Link>

also dont forget to set id='whatever' on the div you want to navigate to.

Hope this helps! :)

dopecello
  • 43
  • 5
1

Following code works fine for me.

<Link className="navlinks1 whitespace-nowrap" href="/#faqs" onClick={(e) => {
            e.preventDefault();
            document.getElementById("faqs").scrollIntoView({ behavior: "smooth" });
          }}>
            FAQs
          </Link>
0

I solved it! You can do this (not globally, but it works fine) with the npm package react-scroll Here is the link: https://www.npmjs.com/package/react-scroll

Manuel Nelson
  • 137
  • 1
  • 1
  • 8
0

Instead of inheriting we can implement Document Component in _document.tsx. creating function component worked for me.

_document.tsx

import { Html, Head, Main, NextScript } from "next/document";

export default function Document() {
  return (
    <Html className='scroll-smooth' >
      <Head/>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

https://nextjs.org/docs/advanced-features/custom-document

pradeexsu
  • 1,029
  • 1
  • 10
  • 27
0

This works fine for me in NextJS

In global.css

* {
    scroll-behavior: smooth;
}

And following code for href I have used:

<a href="#features" className={`${styles.feature} pointer`}>Features</a>
Gvs Akhil
  • 2,165
  • 2
  • 16
  • 33
0

Adding scroll={false} to Link component or simply using HTML's anchor tag solved this.

<Link scroll={false} href='#idname'>
 link name
</Link>

or

<a href='#idname'>
 link name
</a>
aashish-cd
  • 1
  • 1
  • 4
0

For any one using Next 13 (App dir) and above and want to be able to scroll to specific section on the current page or navigate to another page and automaticaly scroll to a specific section and like me has tried everything here and didn't work then checkout this answer.

Firstly Create a Function that Accept a Id String and Scroll the element Into View.

// Handles scrolling of Element to view
export function scrollElementToView(scrollToId: string) {
  const element = document.querySelector(`#${scrollToId}`) as HTMLElement;

  const elRect = element.getBoundingClientRect();

  const scrollDistance = elRect.top + window.scrollY;

  // Incase you want to offset the scroll To view Position.
  const offset = Number(element.getAttribute('data-scroll-to-view-offset')) || 0;

  window.scrollTo({
    top: scrollDistance + offset,
    behavior: 'smooth'
  })
}

Then create a file name ScrollToLinkGlobalComponent and add

'use client';
import React, { useEffect } from 'react';
import { useSearchParams } from 'next/navigation';
import { scrollElementToView } from //whereEver you keep the file



function ScrollToLinkGlobalComponent() {
  const searchParams = useSearchParams();

  useEffect(() => {
    // get element Id from searchParams
    const scrollToId = searchParams.get("scrollToId");

    if (!scrollToId) return; // return if there is none

    scrollElementToView(scrollToId);

  }, [searchParams])

  return null
}

export default ScrollToLinkGlobalComponent

Now Add ScrollToLinkGlobalComponent to your RootLayout. Its should look something like this

*** Imports ***


export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={nunitoSansFont.className}>
      <body>
          {children}
          <ScrollToLinkGlobalComponent />
      </body>
    </html>
  )
}

Then Create a ScrollToLink Component that extends the default Next Link Component.

'use client';
import Link from 'next/link';
import React, { ComponentPropsWithRef } from 'react';
import { useSearchParams } from 'next/navigation';
import { scrollElementToView } from //whereEver you keep the file


interface PropTypes extends ComponentPropsWithRef<typeof Link> {
    scrollToId: string
}



function ScrollToLink({ children, scrollToId, href, ...props }: PropTypes) {
    const searchParams = useSearchParams();


    const persistScrollFeature = () => {
        const urlScrollToId = searchParams.get("scrollToId");

        if (!urlScrollToId || scrollToId !== urlScrollToId) return; //let the Global Component Handle it

        scrollElementToView(urlScrollToId);
    }

    return (
        <Link {...props}
            onClick={persistScrollFeature}
            href={`${href}?scrollToId=${scrollToId}`}
            scroll={false} //very important, its disable nextJs scroll To top on navigation feature
        >
            {children}
        </Link>
    )
}

export default ScrollToLink

Now in any of your Component you can import and use ScrollToLink like this.

<ScrollToLink href="/" scrollToId='hero-section'>Hero Section</ScrollToLink> 
<ScrollToLink href="/" scrollToId='Testimony-section'>Hero Section</ScrollToLink> 

<div id='hero-section'>I am Hero Section</div>
<div id='Testimony-section'>I am Hero Section</div>


//You can offset the scrollToView position like this
<div id='Testimony-section' data-scroll-to-view-offset='-200'>I am Hero Section</div>
Hashira
  • 340
  • 1
  • 6
-1

<style global jsx>
   {`
       html {
          scroll-behavior: smooth;
        }
  `}
  </style>
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 14 '22 at 18:47