'ReferenceError: document is not defined in Next.js while working with React Aria overlays

I'm learning Next.js for web development and I came across commerce, a boilerplate for e-commerce websites written in Next.js. As I was browsing through the code I found the Sidebar component which uses React Aria for creating overlays.

I wanted to use this part in my own project, so wrote a Overlay component that also uses the OverlayContainer component.

import { useRef } from 'react';

import {
    useOverlay,
    useModal,
    OverlayContainer
} from '@react-aria/overlays';

const Overlay = ({ className, children, open = false, onClose }) => {
    const ref = useRef(null);

    const { modalProps } = useModal();

    let { overlayProps } = useOverlay({ onClose: onClose, open: open, isDismissable: true }, ref);
    return (
        <OverlayContainer>
            <div
                {...overlayProps}
                {...modalProps}
                ref={ref}
            >
                {children}
            </div>
        </OverlayContainer>

    );
};

export default Overlay;

This component gets loaded in my Layout component, just as in the commerce project. However, when I try to load up the index page, it gives me the following error:

Server Error
ReferenceError: document is not defined

This error happened while generating the page. Any console logs will be displayed in the terminal window.
Source
pages/_document.tsx (90:33) @ Function.getInitialProps

  88 |     }
  89 | 
> 90 |     const { html, head } = await ctx.renderPage({ enhanceApp })
     |                                 ^
  91 |     const styles = [...flush()]
  92 |     return { html, head, styles }
  93 |   }

When I remove the OverlayContainer component, it loads all fine. I tried updating my dependencies, comparing more code to the Github repo, but nothing found so far.

What's the problem here? And how could I fix it? I'm using Next 10 with React 17.0.1.



Solution 1:[1]

A workaround that you can do is isBrowser which is fairly common for NextJS apps.

const isBrowser = typeof window !== "undefined";

Use it to conditionally render your OverlayContainer.

import { useRef } from "react";

import { useOverlay, useModal, OverlayContainer } from "@react-aria/overlays";

/**
 * Utility to detect if you're on the server, or in the browser.
 */
const isBrowser = typeof window !== "undefined";

const Overlay = ({ className, children, open = false, onClose }) => {
  const ref = useRef(null);

  const { modalProps } = useModal();

  let { overlayProps } = useOverlay(
    { onClose: onClose, open: open, isDismissable: true },
    ref
  );
  return isBrowser ? (
    <OverlayContainer>
      <div {...overlayProps} {...modalProps} ref={ref}>
        {children}
      </div>
    </OverlayContainer>
  ) : null;
};

export default Overlay;

Solution 2:[2]

This happened because Next JS has server-side rendering. When you are using server-side rendering there is no browser. Hence, there is not any variable window or document. Hence this error shows up.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Kevin Wang
Solution 2