Reputation: 335
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'
});
});
}
Upvotes: 18
Views: 71401
Reputation: 71
only need to add scroll-smooth to html tag and it works
{children}Upvotes: 0
Reputation: 1
You can add className="!scroll-smooth" on the layout.js and it will work!
Upvotes: -1
Reputation: 446
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>
);
}
}
Upvotes: 22
Reputation: 1201
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>
Upvotes: 1
Reputation: 1
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>
Upvotes: 0
Reputation: 91
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>
Upvotes: 4
Reputation: 2610
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>
Upvotes: 9
Reputation: 241
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! :)
Upvotes: 1
Reputation: 673
Add scroll-behavior:smooth in html or body. Then adding in
<Link href="#someid" scroll={false}>
works
Upvotes: 44
Reputation: 1
<style global jsx>
{`
html {
scroll-behavior: smooth;
}
`}
</style>
Upvotes: -1
Reputation: 1145
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
Upvotes: 0
Reputation: 224
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!
Upvotes: 2
Reputation: 335
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
Upvotes: -1