NextJS _document is only rendered on the server, so event handlers cannot be used in this file.

Published on November 28th, 2024


Non interactive _document NextJs

If you tried to use state or onclick or any other kind of interactivity in a component imported by the _document file in the nextjs page router like a navbar with onclick property or anyother kind of client-side interactivity in it will fail to work, but it won't throw any kind of error either on the client side nor on the server. I ran into the same error while trying to implement a click dropdown in the globally shared navigation Bar and wasted 3 days trying to fix it.

Suggestions i found online and tried that didn't work

  • Updating/upgrading Node multiple times.
  • Renaming the component with interactive code in it.
  • Creating a new project and moving code

How i eventually fixed it

All you have to do is move the import and declaration of the code that has client side interactivity or state in it from the _document file and put it in the _app.tsx/jsx/js file in the src dir

Former code: _document.tsx:

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

export default function Document() {
  return (
    <Html lang="en">
      <Head/>
      <body className="">
        <TopNav /> //TopNav has client side code
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

_app.tsx:

import "@/styles/globals.css";
import type { AppProps } from "next/app";

export default function App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

New Codes: _document.tsx:

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

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

_app.tsx:

import "@/styles/globals.css";
import TopNav from "@/components/TopNav";
import type { AppProps } from "next/app";

export default function App({ Component, pageProps }: AppProps) {
  return <><TopNav/><Component {...pageProps} /></>;
}

Why this works

_document is only rendered on the server, but __app renders both on the server and client which therefore allows you to add clients side interactivity to your code and it is also shared between all pages.

Alternative fix

Another way to fix it is to move you entire codebase to the newer app routing system which i personally hate

conclusion and why this happens?

The reason this issue occurs is because the _document component renders only on the server then pass compiled html to the client which in other words disables any kind of programmed interactivity you want on the client side and all you need to do is move the code that needs client side interactivity into the _app file which is also shared with all pages

Made With ♥ By Olajide Olanrewaju Monyasau