Updated 23 days ago | GitHub

Modifying Attributes of HTML Elements

The DOM guide showed how document.querySelector creates a reference to an HTML element. Once we have a reference, we can use it to modify the element — starting with its attributes, the name/value pairs like src, href, id, and class that customize an element inside its opening tag (introduced in HTML Elements and Syntax). The later sections cover the closely related task of modifying an element’s contents — what sits between its opening and closing tags.

The setAttribute method

The setAttribute method sets the value of an attribute on an element. If the attribute already exists its value is updated; otherwise a new attribute is added with that name and value.

elementName.setAttribute(name, value);
  • elementName: A variable containing an Element reference, like one returned by document.querySelector.
  • name: A string with the attribute’s name, such as 'src' or 'href'. For HTML elements the name is automatically converted to lowercase.
  • value: A string with the new value. A non-string value is automatically converted into a string.

For example, to point an img element at a different picture and update its text description to match:

const logoImage = document.querySelector('#logo');
logoImage.setAttribute('src', './codepathlogo.jpg');
logoImage.setAttribute('alt', 'CodePath logo');

Reading and removing attributes

Two companion methods round out the basics:

  • getAttribute(name): Returns a string containing the attribute’s value, or null if the element doesn’t have an attribute with that name.
  • removeAttribute(name): Removes the named attribute from the element. Calling it for an attribute the element doesn’t have is not an error — nothing happens.

⚠️ Turn boolean attributes off with removeAttribute, never by assigning null or "false". Attributes like disabled and checked are boolean attributes: the browser treats them as on whenever they are present at all, no matter their value. To turn one on, MDN recommends setting it to the empty string — elementName.setAttribute('disabled', '') — and to turn it off, MDN says to use removeAttribute() rather than setting the value to null, because many attributes will not behave as expected when set to null.

Assigning DOM properties directly

Many attributes are reflected by a property on the element, meaning the attribute’s value can be read or written directly through a JavaScript property — the same . syntax we use with innerHTML below:

const logoImage = document.querySelector('#logo');
logoImage.src = './codepathlogo.jpg'; // setting a reflected property updates the attribute
console.log(logoImage.alt); // reading one returns the attribute's current value

Two differences to keep in mind:

  • Names don’t always match. Reflected properties are usually named in camelCase, so the aria-checked attribute is reflected by the ariaChecked property.
  • Types can differ. getAttribute always returns a string (or null), while a reflected property uses a natural JavaScript type. MDN’s example: for a checkbox input, getAttribute("checked") returns "" or null, while the reflected checked property returns true or false — usually what we actually want in a condition.

Modifying classes with classList

The class attribute is modified from JavaScript so often — think highlighting the active tab, or showing and hiding a pop-up — that the DOM provides a dedicated helper for it. An element’s classList property is a live DOMTokenList representing the class attribute, and MDN describes it as “a convenient alternative to accessing an element’s list of classes as a space-delimited string via element.className”. Instead of editing that string ourselves, we call methods:

const menuElement = document.querySelector('#menu');

menuElement.classList.add('open', 'highlighted'); // adds one or more classes
menuElement.classList.remove('highlighted');      // removes a class
menuElement.classList.replace('open', 'closed');  // swaps 'open' for 'closed'
menuElement.classList.contains('closed');         // returns true
menuElement.classList.toggle('closed');           // 'closed' is present, so this removes it; toggle adds a class when it is absent

Each method leaves the element’s other classes untouched, so styling applied through a different class keeps working.

Introducing the innerHTML property!

The DOM is used to create references to HTML elements. In this section we will look at how the DOM can be used to get or change the contents of an element.

The innerHTML property can be used to get the contents of an Element. Remember that for HTML elements, its contents are what is contained between the opening and closing tags.

Unlike DOM methods (like querySelector), in order to use a property in JavaScript, we use the symbol . after an element, or variable containing an Element type.

elementName.innerHTML = htmlString;
  • elementName.innerHTML: The contents of elementName. Read on its own, this property returns the current contents; in the statement above we are assigning it a new value instead.
  • =: Symbol used to assign a value.
  • htmlString: The new value we want to assign the contents of elementName.
  • ;: A semicolon ends a JavaScript statement. JavaScript can automatically insert most missing semicolons, but always including one is the convention used throughout these guides and avoids ASI pitfalls.

Inserting Elements into the DOM

In the last section we saw how the innerHTML property can be used to replace the contents of an element. To add HTML elements without throwing away what is already there, the preferred approach is insertAdjacentHTML (covered below). Let’s think about why we might add additional HTML elements from the script as opposed to on the HTML document itself!

The HTML document holds the structure, or skeleton, of the website itself. We can manipulate the structure slightly from the script but overall, the structure of the website remains the same from when we initialize it with our index.html page. Let’s think about examples of when we might modify what is visible to the page from the script.

  1. Adding a pop up when a user clicks on a button.
  2. Implementing an “infinite scroll” or adding more results as a user reaches the bottom of our page.
  3. Changing the contents on a page based on user input.
  4. Add status updates for events (uploading, downloading, etc.)

Adding HTML elements on the script side can give users the appearance of a “new” page without reloading the entire page. This can be less demand on the server side with dynamic changes. Let’s take a look at the syntax for injecting HTML elements. The recommended method is insertAdjacentHTML:

divElement.insertAdjacentHTML('beforeend', `
  <!-- Insert HTML elements here -->
  <p>New HTML elements!</p>
`);
  • divElement: When injecting HTML elements, this is typically a div element in the HTML document. This way it is easy to contain or group the new elements together without disrupting the existing layout.
  • insertAdjacentHTML(position, htmlString): Parses htmlString as HTML and inserts the resulting nodes into the DOM at position relative to divElement. Use 'beforeend' to add the new HTML as the last child of divElement, so it appears below any existing children. The other accepted positions are 'beforebegin', 'afterbegin', and 'afterend'.
  • ``: Inside the template literal we put the HTML elements we wish to insert.

⚠️ Avoid divElement.innerHTML += '...'. Older tutorials sometimes teach divElement.innerHTML += '<p>New HTML elements!</p>' for appending. The += form serializes the element’s existing contents back to a string, concatenates the new HTML, then re-parses and replaces everything — which destroys references and event listeners attached to existing children. Per MDN, insertAdjacentHTML “does not reparse the element it is being used on, and thus it does not corrupt the existing elements inside that element. This avoids the extra step of serialization, making it much faster than direct innerHTML manipulation.”