About “ReferenceError: document is not defined” in JavaScript
Tags: javascript, webdev, beginners
Published: 2023-02-06 20:06:08

> ✋ **Update:** This post was originally published on my blog [decodingweb.dev](https://www.decodingweb.dev), where you can read the [latest version](https://www.decodingweb.dev/how-to-solve-referenceerror-document-is-not-defined) 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
```

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](https://www.decodingweb.dev/front-end-skills-to-get-you-started#web-apis) 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. <u>A reference to the `document` object in Node.js</u>
2. <u>Server-side Rendering (SSR)</u>
3. <u>Casing might be off.</u>

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](https://www.decodingweb.dev/front-end-skills-to-get-you-started#javascript-engines).

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

```js
// This code only runs on the browser

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

**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:

```js
// 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.

```js
// 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.

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

```js
// 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!

---

**❤️ You might like:**

- [TypeError: map is not a function in JavaScript (Fixed)](https://www.decodingweb.dev/fix-map-is-not-a-function-error-in-javascript)
- [Add commas to numbers in JavaScript (Explained with examples)](https://www.decodingweb.dev/add-commas-to-numbers-in-javascript)
- [SyntaxError: Unexpected end of JSON input in JavaScript (Fixed)](https://www.decodingweb.dev/syntaxerror-unexpected-end-of-json-input-in-javascript)