Search code examples
javascriptreactjsnext.jsreact-aria

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

  • 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;