Before we jump ahead and look at custom attributes, let's take a quick moment and discuss how to access attributes in general. Let's say that we have an HTML element that looks as follows:
<img id="tv" src="foo.png">
let imgElement = document.querySelector("#tv"); let idValue = imgElement.getAttribute("id"); let srcValue = imgElement.getAttribute("src"); console.log(idValue) // tv console.log(srcValue) // foo.png
For built-in attributes such as the id and src attributes on an image element, we can access them directly by just dotting into it:
let imgElement = document.querySelector("#tv"); let idValue = imgElement.id; let srcValue = imgElement.src; console.log(idValue); // tv console.log(srcValue); // <full-path>/foo.png
Another approach is to use the attributes property on the DOM element and iterate through the attributes, but that is one we can table for later.
Reading attributes is one thing. Setting attributes is a whole another thing which is handled by the setAttribute method takes the attribute name and the new value as its arguments:
let imgElement = document.querySelector("#tv"); imgElement.setAttribute("src", "bar.png"); console.log(imgElement.getAttribute("src")); // bar.png
Notice that we use setAttribute to change the value of the src attribute to be bar.png.
The last basic attribute-related activity we will look at is how to remove attributes. This task is handled by the removeAttribute method:
let imgElement = document.querySelector("#tv"); imgElement.removeAttribute("src"); console.log(imgElement.getAttribute("src")); // undefined
To use the removeAttribute method, what we need to provide is the name of the attribute to remove as shown in the above example. Notice we are removing the src attribute from our image element, and when we try to access the removed attribute, we can see that it returns a value of undefined.
Moving beyond the standard, built-in attributes our elements carry with them, we have the fun world of custom attributes. In the past, if we ever wanted to mark or tag our elements for any sort of programmatic access later, we didn't have too many good choices. The most common thing we did was add or remove class values from an element:
<img class="ufo friendly healthy" src="spaceship.png"> <img class="ufo enemy destroyed" src="spaceship.png">
That was fine if what we were doing resulted in our element visually changing. There are many times when we just want to store some data on an element - data that we wouldn't want to surface to the user. Overloading the more CSS-oriented class attribute seemed a bit distasteful. Also distasteful was abusing the rel tag, declaring custom namespaces, and doing other things to make up for the lack of a standardized way to embed data into our page.
Fortunately, something sweeter was on the horizon. We have the ability to specify custom data attributes (aka data dash or data-* attributes) whose sole job is to allow us to tag elements with data that we can programmatically access later. Let's say that we have a list of images:
<img src="foo.png"/> <img src="bar.png"/> <img src="zorb.png"/> <img src="blarg.png"/>
What we want to do is store the name of the photographer as part of each image. The way we arer going to do this is by using a custom data attribute called photographer:
<img src="foo.png" data-photographer="Bart"/> <img src="bar.png" data-photographer="Lisa"/> <img src="zorb.png" data-photographer="Ralph"/> <img src="blarg.png" data-photographer="Milhouse"/>
Notice how the custom data attribute is defined. Whatever attribute name you are interested in using, simply prefix data- in front of it. You can have as many custom data attributes as you want. In case you were wondering, simply adding a custom data attribute has no bearing on the appearance or layout of an application.
With custom data attributes, the two most common things we will do is retrieve the value stored by such an attribute or set the value stored by such an attribute. What we saw with getAttribute, setAttribute, and removeAttribute work identically here.
To retrieve the value stored by a data-* attribute, use the trusty getAttribute method on the HTML element the attribute lives on:
<img id="tv" src="foo.png" data-photographer="Krusty the Clown"> <script> let tvImg = document.getElementById("tv"); let name = tvImg.getAttribute("data-photographer"); </script>
To set the value, we use getAttribute's mortal enemy, the setAttribute method:
tvImg.setAttribute("data-photographer", "Sideshow Bob");
Ok, there is one thing that custom data attributes have that regular attributes don't. That is the handy dataset property. It makes sense when we look at an example of it in action:
<img id="tv" src="foo.png" data-size="large" data-name="Picasso"> <script> let imgElement = document.querySelector("#tv"); let imgSize = imgElement.dataset.size; let imgName = imgElement.dataset.name; console.log(imgSize); // large console.log(imgName); // Picasso </script>
Notice that we have data-size and data-name as custom attributes. The way we access these attributes is directly via the dataset property and omitting the data- prefix. This handy way of reading custom data properties applies to setting them as well where we can just assign the new attribute value just like we would any variable:
<img id="tv" src="foo.png" data-size="large" data-name="Picasso"> <script> let imgElement = document.querySelector("#tv"); let imgSize = imgElement.dataset.size; imgElement.dataset.name = "Van Gogh"; let imgName = imgElement.dataset.name; console.log(imgSize); // large console.log(imgName); // Van Gogh </script>
Pretty neat, right?
Who knew that something as simple as HTML attributes would take up this many words? The main takeaway is that we have a handful of helpful methods and properties in the DOM that make working with attributes fairly straightforward. The work on our end is to know how to use them and, as often is the case, know what they do when we are reading some code and we run into getAttribute, setAttribute, removeAttribute, or dataset.