How to fix “ReferenceError: document is not defined” in JavaScript

The photo of three guys looking for an address

ReferenceError: document is not defined.

This guide explains why ReferenceError: document is not defined occurs and how you can fix it.

 let element = document.querySelector('#usernameLabel')
              ^

ReferenceError: document is not defined 

The most common reason for "document is not defined" error is that your JavaScript code is trying to access the document object in a non-browser environment, such as Node.js.

A quick intro to the document object (if you're in a hurry, you can jump right to the solutions):

Whenever you access a web page via the web browser, the browser's renderer fetches and parses the HTML code (along with the assets) and stores its elements (headings, paragraphs, images, form elements, etc.) into an internal data structure called DOM

DOM is then turned into Render Tree (consisting of visible elements and their styles), and through a complicated process, the code is turned into pixels - what you see as a user. 

Additionally, the web browser exposes an interface to the DOM tree called DOM API. The DOM API lets you modify the page programmatically via JavaScript to do things like:

  • Set the page title on the fly
  • Add/remove HTML element(s)
  • Manage CSS styles
  • Add/remove CSS classes
  • and a lot more!

And the entry point to this powerful API is the document object. 

What causes ReferenceError: document is not defined

The first thing to know is that the DOM API is a web browser component and not a part of JavaScript. JavaScript only enables you access this object (like any other object).

Here are the possible scenarios that "ReferenceError: document is not defined" error might happen:

  • A reference to the document object in Node.js
  • Server-side Rendering (SSR)
  • Casing might be off.

Let's see how we can fix them.

How to fix "document is not defined" error

1. In Node.js: As mentioned earlier, the document object is a browser feature and not a part of JavaScript. On the other hand, when there's no browser, there's no document object.

With Node.js, you must review the code and figure out why you're accessing a browser object in a server-side code in the first place? Maybe it's just there because you borrowed the code from another file?

However, if your code is used by both the front end and the server, you can place the reference to the document inside a conditional statement - to ensure it'll only run by the browser's JavaScript engine.

To do this, you can place it inside a conditional statement and check for the availability of the document object:

  • conditional-document-reference.js
 // This code only runs on the browser

if (typeof document !== 'undefined') {
   let element = document.querySelector('.class-name')
   
   // Manipulating the DOM here
} 

2. Serverside-rendering (SSR): The "document is not defined" error might also occur when using static site generators, such as Nuxt.js or Next.js, or Gatsby.

A quick fix - as suggested above - is to place any reference to the document object inside a conditional statement - to exclude it from the server-side rendering.

If you use Next.js, you can place your DOM-related code inside a useEffect hook. The callback passed to useEffect runs after the component is mounted (and painted).

The example below is from React's documentation:

  • useeffect-example
 import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = 'You clicked ' + count + ' times';
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
} 

How about Nuxt.js? If you're using Nuxt.js with Vue, and the error is raised in one of your components, you can wrap your component inside a <client-only> component, and the error will go away. 

<client-only> guarantees that your component is only rendered on the client side.

  • nuxtjs-client-only.js
 <template>
  <div>
    <client-only placeholder=" loading...">
      <your-component>
    </client-only>
  </div>
</template> 

Additionally, you can access DOM from within the mounted Vue lifecycle hook.

3. Or maybe it's just a typo? It's also worth checking the document object is all lowercase and not capitalized! 

  • document-reference-case.js
 // ⛔ Wrong
Document.querySelector('.class-name')

// ✅ Correct
document.querySelector('.class-name') 

Wrapping up

In this quick guide, you learned the document object is a browser feature and should always be used in a browser environment.

The most common reason for this error is that the code tries to access the document object in a non-browser environment, such as Node.js.

Two common way to avoid such errors is to use a conditional statement to ensure the code only runs in the browser. Alternatively, you can use hook mechanisms in case you're using an SSR framework such as Next or Nuxt.js.

I hope this guide provided the answer you were looking for.

Thanks for reading!

Author photo

Hey 👋 I'm a software engineer, an author, and an open-source contributor. I enjoy helping people (including myself) decode the complex side of technology. I share my findings on Twitter: @lavary_

If you read this far, you can tweet to the author to show them you care. Tweet a Thanks

In this article:

Disclaimer: This post might contain affiliate links. I might receive a commission if a purchase is made. However, it doesn’t change the cost you’ll pay.