W3docs

Debugging and Tools in Web Development

Learn to debug JavaScript that manipulates the DOM using browser developer tools: inspect elements, use the console, and set breakpoints.

When a script that works with the DOM misbehaves, the fastest way to find out why is to look at the page from the browser's point of view. Browser developer tools (DevTools) let you read the live DOM tree, pause JavaScript mid-execution, and watch exactly what each line does to the page.

This guide covers four practical skills: opening and using DevTools, inspecting elements, logging and stepping through DOM code, and fixing the handful of bugs that account for most DOM problems.

Using Browser Developer Tools

Inspecting the DOM

Browser developer tools are utilities built into modern browsers for inspecting and editing the live DOM, debugging JavaScript, monitoring network requests, and measuring performance. The most useful panels for DOM work are:

  • Elements (Firefox: Inspector) — the live DOM tree and the CSS that applies to each node.
  • Console — logs, errors, and a REPL where you can run JavaScript against the current page.
  • Sources (Firefox: Debugger) — your scripts, where you set breakpoints and step through code.

A key point that trips up beginners: the Elements panel shows the live DOM, not the HTML you wrote. If your script adds, removes, or rewrites nodes, the Elements panel reflects the result after the script ran — which is exactly what you want when debugging DOM manipulation.

How to Open Developer Tools

  • Chrome: Right-click on the page and select "Inspect", or press Ctrl+Shift+I (Windows/Linux) or Cmd+Opt+I (Mac).
  • Firefox: Right-click on the page and select "Inspect Element", or press Ctrl+Shift+I (Windows/Linux) or Cmd+Opt+I (Mac).
  • Safari: Enable the Develop menu in Preferences, then select "Show Web Inspector" from the Develop menu.

Inspecting Elements

The "Elements" panel allows you to inspect and edit the HTML and CSS of a webpage in real-time.

<!DOCTYPE html>
<html>
<head>
    <title>Inspecting Elements</title>
    <style>
        .highlight {
            color: red;
        }
    </style>
</head>
<body>
    <div class="content">This is some content.</div>
    <script>
        document.querySelector('.content').classList.add('highlight');
    </script>
</body>
</html>

Use the Elements panel (press F12 to open the Inspector, then navigate to the Elements tab) to inspect the <div class="content"> element and verify that the .highlight class is applied.

Debugging JavaScript that Manipulates the DOM

Using the Console

The console is the quickest debugging tool: drop a log statement, reload, and read the output. Beyond the basic console.log(), several methods make DOM debugging much clearer:

  • console.log() — general output; pass several arguments and they print side by side.
  • console.error() / console.warn() — styled red/yellow messages that are easy to spot and can be filtered.
  • console.dir(node) — prints a DOM node as a JavaScript object so you can expand its properties, rather than as HTML (which is what console.log(node) shows).
  • console.table(data) — renders arrays and objects as a sortable table.
  • console.assert(condition, msg) — logs only when the condition is false, perfect for sanity checks.
  • console.count(label) — counts how many times a line runs, useful for spotting an event handler that fires too often.
const items = [
  { id: 1, name: 'Alpha' },
  { id: 2, name: 'Beta' },
];

console.log('Loaded items:', items.length); // Loaded items: 2
console.table(items);                        // sortable table of both rows
console.assert(items.length > 0, 'No items!'); // silent: condition is true
console.assert(items.length > 5, 'Too few items'); // logs the assertion message

When you log a DOM node, prefer console.dir(el) to inspect its properties (such as el.dataset or el.classList) and console.log(el) to inspect its rendered HTML — they show two different views of the same element.

Setting Breakpoints

Breakpoints allow you to pause the execution of JavaScript at specific lines of code to inspect variables and the call stack.

How to Set Breakpoints

  1. Open the "Sources" panel in Chrome or the "Debugger" panel in Firefox.
  2. Navigate to the JavaScript file you want to debug.
  3. Click on the line number where you want to set a breakpoint.

When execution pauses, use the stepping controls: Step over (run the current line), Step into (enter a called function), and Step out (finish the current function). The Scope pane shows local variables, and Call Stack shows how you got to this line.

The debugger statement

You can also pause from code itself. When DevTools is open, the debugger; statement acts like a breakpoint that lives in your source — handy for code that is generated at runtime or that you cannot easily click in the Sources panel:

function updateTitle(text) {
  debugger; // execution pauses here when DevTools is open
  document.title = text;
}

If DevTools is closed, debugger does nothing, so it is safe to leave in during development (but remove it before shipping).

Conditional and logpoint breakpoints

For a handler that runs many times, right-click a line number and choose Add conditional breakpoint to pause only when an expression is true (for example count > 100). A logpoint prints a message without pausing at all — like a console.log() you can add without editing the source.

Example of Debugging DOM Manipulation

<!DOCTYPE html>
<html>
<head>
    <title>Debugging Example</title>
</head>
<body>
    <div id="content">Hello, World!</div>
    <button id="change-text">Change Text</button>
    <p id="log"></p>

    <script>
        document.getElementById('change-text').addEventListener('click', function() {
            const content = document.getElementById('content');
            const log = document.getElementById('log');
            log.textContent = 'Current text: ' + content.textContent;
            content.textContent = 'Hello, Developer!';
            log.textContent += ' | Updated text: ' + content.textContent;
        });
    </script>
</body>
</html>

This example demonstrates how to debug DOM manipulation by displaying the changes in the DOM.

Common Issues and Solutions

Troubleshooting Common DOM Manipulation Problems

  1. Element Not Found

    The most common DOM error is a TypeError: Cannot read properties of null. It means a selector returned null because the element does not exist (a typo in the id, or the wrong selector). Always check the result before using it. See Searching: getElement, querySelector for the difference between selector methods.

const element = document.getElementById('nonexistent');
if (element) {
    element.textContent = 'Found!';
} else {
    document.body.insertAdjacentHTML('beforeend', '<p>Element not found</p>');
}
  1. Incorrect Timing

    If a <script> in the <head> runs before the body is parsed, the elements it looks for do not exist yet — producing the same null error as above. Run DOM code after the document is parsed by listening for the DOMContentLoaded event (or by placing the script at the end of <body>).

document.addEventListener('DOMContentLoaded', function() {
    const element = document.getElementById('content');
    element.textContent = 'DOM fully loaded';
});
  1. CSS Not Applied

    If a style change has no visible effect, confirm in the Elements panel that the class was actually added (element.classList) and that no more-specific rule overrides it — DevTools shows overridden rules with a strikethrough. Related: Event handling in the DOM.

<!DOCTYPE html>
<html>
<head>
    <title>CSS Not Applied</title>
    <style>
        .hidden {
            display: none;
        }
    </style>
</head>
<body>
    <div id="content">This is visible</div>
    <button id="hide-content">Hide Content</button>

    <script>
        document.getElementById('hide-content').addEventListener('click', function() {
            const content = document.getElementById('content');
            content.classList.add('hidden');
        });
    </script>
</body>
</html>

This example demonstrates hiding a content element by adding the .hidden class.

Info

Use the "Sources" panel in browser developer tools to set breakpoints and step through your JavaScript code line-by-line. This allows you to inspect variables, the call stack, and the state of the DOM at each step, making it much easier to identify and fix bugs.

Conclusion

Browser developer tools are indispensable for inspecting the DOM, debugging JavaScript, and troubleshooting common issues. By mastering these tools and techniques, you can significantly improve your development workflow and build more reliable web applications.

Practice

Practice
Which of the following statements about debugging and tools for DOM manipulation are true?
Which of the following statements about debugging and tools for DOM manipulation are true?
Was this page helpful?