# Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')

You added a button and a few lines of JavaScript to make it do something. You click it, nothing happens, and the browser console says:

```
Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')
```

The message sounds technical, but it says something simple: JavaScript didn't find your element. Here's how to read it, the mistakes that cause it almost every time, and a few related errors that look alike.

## What the error means

Read it from the end:

- `(reading 'addEventListener')`: your code tried to use `addEventListener` on something.
- `of null`: that something was `null`, which means "nothing".
- `Cannot read properties`: you can't call anything on nothing.

So the variable you called `addEventListener` on is `null`. Where did it come from? Almost always from a line like this, just above:

```js
// app.js
const button = document.querySelector("#color-btn");
```

`document.querySelector` gives back the first element that matches the selector, or `null` if nothing on the page matches. Then the next line fails:

```js
// app.js
button.addEventListener("click", () => {
  document.body.style.background = "lightyellow";
});
```

The error also stops your script at that line, so nothing written after it runs either.

## Cause 1: a missing # in the selector

`querySelector` uses CSS selectors. An id needs a `#` in front, and a class needs a `.`:

```html
<!-- index.html -->
<button id="color-btn">Change color</button>
<script>
  const button = document.querySelector("color-btn");
  button.addEventListener("click", () => {
    document.body.style.background = "lightyellow";
  });
</script>
```

Without the `#`, `"color-btn"` means "an element whose tag name is color-btn", like `<color-btn>`. There's no such tag on the page, so you get `null`.

The fix is one character:

```js
const button = document.querySelector("#color-btn");
```

Or use `getElementById`, which takes the id without the `#`:

```js
const button = document.getElementById("color-btn");
```

Check the spelling too: `color-btn` in the HTML and `colour-btn` in the JavaScript are different ids, and the result is the same error.

## Cause 2: the script runs before the element exists

This version has a perfect selector and still fails:

```html
<!-- index.html -->
<!DOCTYPE html>
<html>
  <head>
    <script src="app.js"></script>
  </head>
  <body>
    <button id="color-btn">Change color</button>
  </body>
</html>
```

The browser reads the page from top to bottom. It reaches the `<script>` in the `<head>` and runs `app.js` right away, before it has read the `<body>`. At that moment the button doesn't exist yet, so `querySelector` returns `null`.

You have three ways to fix it. Any one is enough:

1. Move the `<script>` to the end of the `<body>`, just before `</body>`.
2. Keep it in the `<head>` but add `defer`: `<script src="app.js" defer></script>`. The browser then runs it after the page has been read.
3. Wrap your code so it waits for the page:

```js
// app.js
document.addEventListener("DOMContentLoaded", () => {
  const button = document.querySelector("#color-btn");
  button.addEventListener("click", () => {
    document.body.style.background = "lightyellow";
  });
});
```

## Cause 3: an id that's really a class

The selector has to use the same kind of name as the HTML. Here the button has a class, but the selector looks for an id:

```html
<!-- index.html -->
<button class="color-btn">Change color</button>
<script>
  const button = document.querySelector("#color-btn");
  button.addEventListener("click", () => {
    document.body.style.background = "lightyellow";
  });
</script>
```

`#color-btn` only matches `id="color-btn"`, so `querySelector` returns `null` and you get the same error. Match the selector to the HTML: `".color-btn"` for a class, `"#color-btn"` for an id. And remember that `getElementById` only finds ids: it never finds an element by its class.

## Cause 4: one script, several pages

Your site has a home page with the button and an About page without it, and both load the same `app.js`. On the home page everything works. On the About page, the console shows the error, and anything after that line in `app.js` doesn't run there either.

The script isn't wrong; the element isn't on every page. Only add the listener when the element exists:

```js
// app.js
const button = document.querySelector("#color-btn");
if (button) {
  button.addEventListener("click", () => {
    document.body.style.background = "lightyellow";
  });
}
```

Or, shorter, with the `?.` operator, which skips the call when the value is `null`:

```js
// app.js
button?.addEventListener("click", () => {
  document.body.style.background = "lightyellow";
});
```

Use this only when the element is really optional. If it should be on the page, a silent `?.` hides the real problem: fix the selector or the script's position instead.

## Errors that look alike

### addEventListener is not a function

`getElementsByClassName` and `querySelectorAll` don't return one element, but a list of all matches. A list has no `addEventListener`, so this fails with a different message:

```js
// app.js
const buttons = document.querySelectorAll(".btn");
buttons.addEventListener("click", () => {});
```

```
Uncaught TypeError: buttons.addEventListener is not a function
```

Add the listener to each element in the list instead:

```js
// app.js
const buttons = document.querySelectorAll(".btn");
buttons.forEach(button => {
  button.addEventListener("click", () => {
    console.log("clicked", button.textContent);
  });
});
```

### Cannot read properties of undefined (reading 'addEventListener')

`undefined` instead of `null` usually means you took an item from a list that was empty: `document.getElementsByClassName("btn")[0]` gives `undefined` when there's no element with that class. The causes and fixes are the same as above: check the class name and where the script runs.

### Cannot set properties of null (setting 'textContent')

If you assign to the element instead of calling a method on it, like `document.querySelector("#total").textContent = "5";`, Chrome says `Cannot set properties of null (setting 'textContent')`. It's the same problem: the element wasn't found.

### In Firefox and Safari

Other browsers word it differently. Firefox says something like `button is null`, and Safari something like `null is not an object (evaluating 'button.addEventListener')`. Whatever the wording, it means the same thing: the value before the dot is `null`.

If the problem is the opposite one, your styles not showing up instead of your script failing, see [CSS not working? 7 reasons your styles don't apply](https://craftstackacademy.com/blog/css-not-working-why-styles-dont-apply).

## How to find the culprit quickly

1. Open the console (F12 in most browsers, then the **Console** tab) and click the file name and line number next to the error. It takes you to the line that failed.
2. Look at the variable before the dot, here `button`, and find the line that created it.
3. Log it: `console.log(button);`. If the console shows `null`, the selector found nothing.
4. Compare the selector with the HTML: the `#` or `.`, the spelling, and whether the element is above or below your script.

The same pattern explains its cousins: `(reading 'textContent')`, `(reading 'value')` or `(reading 'appendChild')` all mean that the element before the dot is `null`.

The same three questions (what went wrong, where, and what it asks about your code) work for errors in other languages too: [How to Read an Error Message: A 3-Step Method for Python, Java, JavaScript and SQL](https://craftstack.hashnode.dev/how-to-read-an-error-message-a-3-step-method-for-python-java-javascript-and-sql).

We checked every example in this article in Chrome, which writes the messages exactly as shown. If you're just starting with JavaScript, our guide [Which programming language should you learn first?](https://craftstackacademy.com/blog/which-programming-language-to-learn-first) explains where it fits next to HTML and CSS.

In our [Web course](https://craftstackacademy.com/courses/web), this error is one of the first things you meet when your JavaScript starts talking to the page, and the AI tutor helps you read the console instead of guessing. You can start with the free Web trial, "Your Card on the Web": one 20-minute session where you build a profile card with HTML and CSS, with nothing to install: [craftstackacademy.com/trial](https://craftstackacademy.com/trial).

*This article was first published on the [Craftstack Academy blog](https://craftstackacademy.com/blog/javascript-cannot-read-properties-of-null-addeventlistener).*

