18

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'
    });
 });

}

13 Answers 13

44

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

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

works

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks buddy. I was facing similar issue and didn't knew that there is a scroll props to nextjs Link. It was helpful.
this doesnt work for me. Maybe because im in app router?
21

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 Comments

This will add unwanted scroll on page route as well.
It doesn't work on Safari as well
11

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>

2 Comments

I confirm this works with Next.JS even with react-custom-scrollbars-2
Confirmed. Works with <Link> component too.
4

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>

Comments

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!

Comments

1

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>

Comments

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

1 Comment

Try to add clear concept
0

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! :)

Comments

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>

Comments

-1

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

1 Comment

adding a 3rd party package for a simple thing is not a good practice at all.
-1

<style global jsx>
   {`
       html {
          scroll-behavior: smooth;
        }
  `}
  </style>

1 Comment

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.
-1

You can add className="!scroll-smooth" on the layout.js and it will work!

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
-1

only need to add scroll-smooth to html tag and it works

{children}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.