DEV Community

Cover image for About “ReferenceError: document is not defined” in JavaScript
Reza Lavarian
Reza Lavarian

Posted on • Originally published at decodingweb.dev

About “ReferenceError: document is not defined” in JavaScript

Update: This post was originally published on my blog decodingweb.dev, where you can read the latest version for a 💯 user experience. ~reza

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
Enter fullscreen mode Exit fullscreen mode

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:
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 (Document Object Model).

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:

  1. Set the page title on the fly
  2. Add/remove HTML element(s)
  3. Manage CSS styles
  4. Add/remove CSS classes
  5. 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:

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

Let's see how we can fix them.

How to fix "document is not defined" error

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:

// This code only runs on the browser

if (typeof document !== 'undefined') {
   let element = document.querySelector('.class-name')

   // Manipulating the DOM here
}
Enter fullscreen mode Exit fullscreen mode

Serverside-rendering (SSR): The "document is not defined" error might also occur when using static site generators, such as Nuxt.js, 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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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

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')
Enter fullscreen mode Exit fullscreen mode

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!


❤️ You might like:

Top comments (0)