JavaScript DOM Manipulation — Spot the Bug!
This is a daily Javascript challenge from the CodeShot archive. Practice your knowledge of Queryselector Null ClassList Bug and improve your technical interview readiness.
const btn = document.querySelector(".my-button")
btn.classList.add("active")
Detailed Explanation
Why This Question Matters
If you've spent any time in the browser console, you've probably run into a TypeError: Cannot read properties of null (reading 'classList'). It’s practically a rite of passage for junior JavaScript developers.
The snippet we're looking at seems foolproof. You grab an element, you add a class. Simple, right? But in the real world, DOM manipulation isn't just about the syntax—it's about timing and existence. The "bug" in these types of challenges usually isn't a typo in the method name; it's a failure to account for the fact that the DOM might not be ready, or the element might not even exist on the page.
Understanding why this fails is the difference between writing code that "works on my machine" and writing production-ready code that doesn't crash when a user hits a specific route.
Understanding the Code
Let's look at the two lines we have:
Line one uses document.querySelector. This is the Swiss Army knife of DOM selection. It looks for the first element in the document that matches the CSS selector .my-button.
Line two assumes that btn actually contains an element. It accesses the classList property (which is a DOMTokenList) and calls the add() method to inject the "active" class into the HTML.
Internally, if querySelector finds a match, it returns an Element object. If it doesn't find anything, it returns null.
Here is the catch: null does not have a classList property. When the engine hits line two and finds that btn is null, it throws an error and stops execution of your script entirely.
Finding the Correct Answer
In this challenge, the correct answer is Option B, which likely points to the fact that the element might be null or the script is running before the HTML has finished loading.
Why not the other options?
Some might guess that .classList.add() is the wrong method or that you need to use setAttribute. While you *could* use setAttribute('class', 'active'), that's a terrible idea because it overwrites every other class the button already has. classList.add is the industry standard for a reason.
The real issue is the lack of a safety check. To make this code robust, you need to ensure the element exists before you try to touch its properties.
The "pro" way to write this would be using optional chaining:
Or a simple
if block:Common Mistakes Developers Make
The most common mistake I see is placing the tag in the of the HTML document without using the defer attribute.
If your script runs before the browser has parsed the , querySelector will return null because the button literally doesn't exist yet. The browser reads the page from top to bottom. If the JS executes at line 10 and the button is defined at line 50, you're going to have a bad time.
Another common trip-up is the difference between querySelector and querySelectorAll.
- querySelector returns one element.
- querySelectorAll returns a NodeList (which looks like an array).
If you accidentally used querySelectorAll, calling .classList.add() would fail immediately because you can't add a class to a list; you have to loop through the list and add the class to each individual element.
Real-World Usage
In a production environment, you rarely have a single static HTML page. You're dealing with components, dynamic imports, and asynchronous data.
Imagine you're building a navigation bar where the "active" state changes based on the current URL. You might have a script that runs on every page load to highlight the current link. If you have a "Contact" link in your nav but you're on a page where that specific link is hidden or renamed, a blind querySelector will crash your entire JS bundle.
In large-scale apps, we use "Guard Clauses." Instead of nesting your logic in deep if statements, you exit early:
This prevents the error and gives you a helpful log in the console to debug why the element is missing.
Key Takeaways
- Never trust the DOM. Always assume that an element might be missing, especially if your code is shared across multiple pages.
- Check for null. Use optional chaining (?.) or if statements to prevent TypeError crashes.
- Mind the placement. Ensure your scripts run after the DOM is loaded (use defer or place the script at the end of the ).
- Prefer classList over className. It's cleaner and prevents you from accidentally wiping out existing classes on an element.
Why this matters
Understanding Queryselector Null ClassList Bug is crucial for passing technical interviews. In real-world applications, this concept often leads to subtle bugs if not handled correctly. For more details, you can always refer to the official MDN Documentation.