Skip to content

Interacting With The DOM

One of the best things about using a framework like React is that we don't have to fuss with the DOM directly. We tell React what the DOM should look like, and React takes care of creating/modifying/moving/deleting the DOM nodes for us.

That said, I believe it's still worth knowing a little bit about how these operations work. React is using them under-the-hood for us, after all!

In this lesson, we'll dig into some of the most common DOM operations.

Selecting nodes

Let's say we want to grab a reference to an element that already exists on the page.

We can do this with the querySelector method:

// Grab the <body> tag:
const body = document.querySelector('body');

querySelector uses CSS selectors like .some-class and #some-id. If you've written it in CSS, it will work with querySelector:

const enabledButton =
document.querySelector('button:not(:disabled)');
const thirdNavLink =
document.querySelector('.nav-link:nth-of-type(3)');

It's common to call this method on document, since it's the top-level DOM node on the page, but we can actually call it on any DOM node! This allows us to search in a more-precise way:

// Grab the header
const header = document.querySelector('#header');
// Find the first `<a>` tag inside the header
const firstLink = header.querySelector('a');
// ^^^^^^ header, not document!

Sometimes, multiple elements on the page will match the provided query. querySelector will grab the very first one it finds. There's another method, querySelectorAll, which will collect an array-like object of all the matched elements.

If querySelector can't find a matching element, it'll return null.

Once we've captured a reference to a DOM node, we can do a bunch of stuff with it. Let's examine some of the operations at our disposal.

Editing nodes

Let's imagine that we have a list of users in our HTML. If the user is currently online, a little green dot is shown. The markup looks like this:

<ul>
<li id="user-andrew" class="offline">
Andrew
<li>
<li id="user-beatrice" class="offline">
Beatrice
<li>
<li id="user-chen" class="online">
Chen
<li>
</ul>

Suppose we want to toggle the first user, Andrew, from offline to online, by changing the class attribute. We can do this with the setAttribute method:

Code Playground

const node = document.querySelector('#user-andrew');

node.setAttribute('class', 'online');
result

What if we want to change the text within an element? For example, maybe we want to change Andrew's username to Andrew (online).

We can do that with the innerText property:

const node = document.querySelector('#user-andrew');
node.innerText = 'Andrew (online)';

innerText is a writeable property, not a method. Instead of calling it as a function, we re-assign its value to the text content we want to include.

Creating and appending nodes

Finally, let's talk about creating brand-new DOM nodes from scratch!

We can do that using the document.createElement:

const element = document.createElement('div');

createElement takes 1 parameter, which serves as the tag to be created. We can pass any valid HTML tag (eg. 'a', 'ul', 'footer').

A newly-created element has no attributes and no content. We can enhance it using the methods and tools we've seen so far. For example:

Code Playground

const element = document.createElement('div');

element.setAttribute('style', 'color: red;');
element.innerText = "Hello world!";

// Something's missing...
result

Something curious is happening here, though… We've created an element, but we don't see it anywhere on the page!

The reason for this is that while we've created a DOM node, we haven't attached it anywhere. It's in limbo right now, floating in space.

We can fix this with the appendChild method:

const body = document.querySelector('body');
body.appendChild(element);

Try copying this code to the playground above, underneath the code that's already there. The red "Hello world!" text should show up!

Most of the methods we've seen, like querySelector and appendChild, can be called on any DOM node. createElement is different: it can only be called on the document object.

In order for a DOM node to be visible to the user, it needs to be within the <body> tag. The user won't see any HTML tags in other parts of the page. And so when we create an element, it's associated with the document, but it won't be visible until we append it somewhere within the <body>.

Destroying nodes

We can destroy a node using the remove method:

const elem = document.querySelector('#some-element');
elem.remove(); /* No more element! 💨 */

Letting React do it for us

It's good to know that these sorts of methods exist, to give us a sense of what React is doing under-the-hood. Ultimately, though, we generally don't need to do a ton of DOM manipulation with React.

And that's a very good thing. I've worked on large projects that involved a lot of hands-on DOM manipulation, and inevitably, we'd wind up with sticky spaghetti code. It becomes really hard to keep track of which code is doing which manipulations.