Home > Software design >  How to smooth-scroll to an anchor tag from another page in NextJS?
How to smooth-scroll to an anchor tag from another page in NextJS?

Time:06-30

I have 2 pages in my NextJS (1 is Home and another is Leaderboard page). And I have a navbar as such:

<div className={styles.navItem}>
        <Link href="/">
          <a className={styles.navLinks} onClick={toggle}>
            Home
          </a>
        </Link>
      </div>
      <div className={styles.navItem} onClick={toggle}>
        <Link href="/">
          <a
            className={styles.navLinks}
            onClick={setTimeout((e) => {
              document.getElementById("about") &&
                document
                  .getElementById("about")
                  .scrollIntoView({ behavior: "smooth", block: "end" });
            }, 2000)}
          >
            About Us
          </a>
        </Link>
      </div>
      <div className={styles.navItem} onClick={toggle}>
        <Link href="/">
          <a
            className={styles.navLinks}
            onClick={setTimeout((e) => {
              document.getElementById("program") &&
                document
                  .getElementById("program")
                  .scrollIntoView({ behavior: "smooth", block: "end" });
            }, 2000)}
          >
            Program Overview
          </a>
        </Link>
      </div>
      <div className={styles.navItem}>
        <Link href="/leaderboard/">
          <a className={styles.navLinks} onClick={toggle}>
            Leaderboard
          </a>
        </Link>
      </div>

I thought that maybe by using a setTimeout delay it would, redirect me first to the homepage (when I click the Link tag) and then, after 2 seconds, it would smooth scroll me to the section I wanted to go to. But this produces an error document is not defined and when I reload the page, the page would smooth-scroll to #program after 2 seconds even without clicking on the tag. What am I doing wrong?

ERROR (ON TERMINAL)

error - components/main/Nav/MenuRight.js (18:23) @ Timeout.eval [as _onTimeout]
ReferenceError: document is not defined
  16 |         <Link href="/">
  17 |           <a
> 18 |             className={styles.navLinks}
     |                       ^
  19 |             onClick={() =>
  20 |               setTimeout((e) => {
  21 |                 document.getElementById("about") &&

CodePudding user response:

Your problem is you call setTimeout directly which is executed right away on the server (more specifically, NextJS does not have window and document objects on the server-side) that's why document is not available.

You should wrap it into a function like below and onClick will be only triggered once you click on that element

<div className={styles.navItem}>
        <Link href="/">
          <a className={styles.navLinks} onClick={toggle}>
            Home
          </a>
        </Link>
      </div>
      <div className={styles.navItem} onClick={toggle}>
        <Link href="/">
          <a
            className={styles.navLinks}
            onClick={(e) => {
             setTimeout(() => {
              document.getElementById("about") &&
                document
                  .getElementById("about")
                  .scrollIntoView({ behavior: "smooth", block: "end" 
              });
            }, 2000)
            }}
          >
            About Us
          </a>
        </Link>
      </div>
      <div className={styles.navItem} onClick={toggle}>
        <Link href="/">
          <a
            className={styles.navLinks}
            onClick={(e) => {
               setTimeout(() => {
                 document.getElementById("program") &&
                   document
                     .getElementById("program")
                     .scrollIntoView({ behavior: "smooth", block: "end" });
               }, 2000)
            }}
          >
            Program Overview
          </a>
        </Link>
      </div>
      <div className={styles.navItem}>
        <Link href="/leaderboard/">
          <a className={styles.navLinks} onClick={toggle}>
            Leaderboard
          </a>
        </Link>
      </div>
  • Related