Search code examples
reactjsnext.js

Workaround for Next.JS error "referenceError: document is not defined" for an external library component?


I am having some troubles integrating a component from the outside library 'react-calendly', the PopUpButton widget specifically, that requires the parent DOM node to be inserted into. My current understanding is that my issue is being caused by the fact that Next.js uses SSR and therefore I do not have access to the browser. How can I work around this? For reference, my website is a very simple fullstack app for his business and I am new to React/full-stack development. Here is the code for the app portion that renders my page components:

import '../styles/globals.css'
import styles from '../styles/App.module.css'
import Navbar from '../components/navbar'
import Footer from '../components/footer'

function MyApp({Component, pageProps}) {

  return (
    <div className={styles.app}>
      <div>
        <Navbar />
      </div>
      <div className={styles.body} id="body">
        <Component props={pageProps} />
      </div>
      <div>
        <Footer className={styles.footer}/>
      </div>
    </div>
  )
}

export default MyApp

And here is the code for my specific page component:

import styles from '../styles/Home.module.css'
import Head from 'next/head'
import { PopupButton } from 'react-calendly'

export default function Home() {
  
  return (
    <div className="home">
      <Head>
        <title>Homepage</title>
      </Head>
      <div className="cal_div">

        <PopupButton
          url="https://calendly.com/my_url"
          rootElement={document.getElementsById("body")}
          text="Click here to schedule!"
        />
      </div>
    </div> 
  )
}


Solution

  • I actually managed to fix this issue for the exact same case next.js and react.js

    The architecture is as follow:

    1. Calendly calling react component -> 2. dynamic calendly __next component -> 3. calendly child

    1. The React Parent Component:

    'use client';
    import React from "react";
    import CalendlyDynamic from "./Components/CalendlyDynamic";
    
    export default function Home(){
    
    return (
            <div>
                 <CalendlyDynamic />
                 <div id="__next"></div>
            </div>
    )}
    

    1. -> 2. The Calendly dynamic Component:

    import dynamic from "next/dynamic";
    
    const Calendly = dynamic(() => import("../Components/Calendly"), {
      ssr: false
    });
    
    
    export default function Home() {
      return (
        <div>
          <Calendly />
        </div>
      );
    }
    

    2. -> 3. The Calendly Child

    'use client'
    import { PopupButton } from "react-calendly";
    import { useEffect, useState } from "react";
    
    export default function Calendly() {
      const [rootElement, setRootElement] = useState(null);
    
      useEffect(() => {
        // Wait for the component to be mounted before setting the rootElement
        if (typeof window !== "undefined") {
          setRootElement(document.getElementById("__next"));
        }
      }, []);
    
      return (
        <div className="cal_div">
          <PopupButton
            className="rounded-md bg-primary py-4 px-8 text-base font-semibold text-white duration-300 ease-in-out hover:bg-primary/80"
            url="https://calendly.com/your-link"
            rootElement={rootElement}
            text="Schedule Appointment"
          />
        </div>
      );
    }