How to Use HTML Data Attributes 
Tags: html, javascript, css, beginners
Published: 2020-10-29 19:02:47

HTML 5 isn't exactly new anymore (it debuted in late 2014), but its features aren't as well known as the more venerable areas of HTML. Sometimes this is due to a lack of browser support, sometimes to developers clinging needlessly to jQuery, sometimes to a team trying to maintain a large, cumbersome site that predates HTML 5. For those of us with the freedom to embrace all that HTMl 5 has to offer, there's a lot of power to be had. **Data attributes** are one of the more powerful additions to arrive in HTML 5.

# Data Attributes in HTML

It's quite common to use attributes in our HTML. We might use the `class` attribute to apply a CSS class to an element, write into the `style` attribute to override, test, or debug the stylesheet, or add a boolean attribute like `required` to `input` elements in a form. The big distinction between data attributes and attributes on the whole is that **data attributes are defined by the developer** and not built into HTML from the start. Data attributes are hooks that we can set up to provide new ways for our HTML to communicate with our CSS and our JavaScript.

## Creating an HTML Data Attribute

Adding a data attribute is easy. Any HTML element can have any number of data attributes added to its opening tag. We simply type `data-` followed by the name of our attribute into the element's opening tag alongside any other attributes we're already using. 

For example, let's create a data attribute called "badges" and use it to attach a number to a `p` element.

```html
<p data-badges="3">This is a paragraph element.</p>
```

# Data Attributes in CSS

There are two ways we can easily look at our data attributes from our stylesheet. The first is attribute selectors, and the second is the `attr()` function.

## Using Attribute Selectors in CSS

We can target HTML attributes when we're writing CSS rules. A common use for this is selecting certain types of input elements by writing rules for something like `input[type="checkbox"]`. Really **any attribute can be a selector in our CSS rules**. Using data attributes to apply styles this way can make stylesheet organization better by reducing helper classes; instead of creating arbitrary classes like `.one-badge`, `.two-badges`, `.three-badges`, and attaching them manually to elements, we can target a data attribute to apply the desired styles and cultivate a more semantic stylesheet. Our intentions will be more clear when other people (or our future selves) drop in to read our CSS.

So for example, if we wanted to style our paragraph with the “badges” data attached, we could check that data attribute using square braces `[ ]` in our stylesheet.

```css
p[data-badges=“1”] {
  background: orange;
}
p[data-badges=“2”] {
  background: gold;
}
p[data-badges=“3”] {
  background: lime;
}
```

This makes it more obvious where our logic for changing `background` values is coming from than opaquely slapping helper classes on `p` elements would.

## Using the `attr()` Function in CSS

The `attr()` function allows us to **pull data into our CSS** stylesheet from our HTML document. This allows us to move further away from the manual application of styles provided by attribute selectors and closer to treating a data attribute like a variable.

CSS rules are applied to HTML elements that match the selectors enclosing those rules. The `attr()` function lets us grab data from the element that we're selecting and styling. To do this, use `attr()` and pass it the name of your desired data attribute as an argument.

For example, let's display the value of a data attribute after our paragraph element. We just need to add a CSS rule to our stylesheet.

```css
p::after {
  content: attr(data-badges);
}
```

# Data Attributes in JavaScript

JavaScript allows us to complete the transition away from _manually_ attaching data to elements. Data attributes are a great way to endow HTML elements with extra information, but getting and setting the data from these attributes with JavaScript is what really makes this feature useful. Like writing them into HTML and targeting them with CSS, HTML 5 makes working with data attributes in JavaScript very easy.

## Reading HTML Data Attributes in JavaScript

All of an HTML element's data attributes are accessible at `Element.dataset`. This object `dataset` is a DOMStringMap with each data attribute attached as a child. Simply drill down through `dataset` and request your attribute by name.

```javascript
// Start by grabbing our paragraph element
var element = document.querySelector('p');

// Now we can check the value of our data attribute
var badges = element.dataset.badges;
console.log('Badges data attribute value:', badges);
```

## Setting HTML Data Attributes in JavaScript

When we want to set a new value for a data attribute, we can use the same JavaScript function that we'd use for setting any built-in HTML attribute: `setAttribute()`.

```javascript
// We can set our data attribute to 4
element.setAttribute('data-badges', '4');
```

Notice that here we include `data-` before the name of our attribute since this function isn't specific to data attributes.

# Support and Accessibility Notes

As always, be sure to check how widely supported features of the web are before you use them in production. HTML data attributes enjoy quite wide support with one caveat: older versions of Internet Explorer don't support `Element.dataset`. To cater to that userbase (0.34% of users at time of writing), you can use `Element.getAttribute()` just the way `Element.setAttribute()` is discussed above. Simply pass only one argument--the name of the attribute that you're trying to grab--and that attribute's value will be returned to you.

```javascript
// We can still read a data attribute's value without dataset
var badges = element.getAttribute('data-badges');
```

Accessibility is a larger concern; always take the time to make your web creations as broadly accessible as you can. We need to make web technologies and learning resources freely available to ensure the **growth and development of the web as a public platform**.

The **main accessibility concern** in using data attributes is that assistive technology might not read them. Information that is important to the user should never be stated _solely_ in a data attribute; be sure to restate any public-facing information in a traditional element on your page.

# Putting Everything Together 

Let's put together another example that uses data attributes across HTML, CSS, and JavaScript. Let's start with a blank HTML page.

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Data Attributes</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style></style>
</head>
<body>
  <script></script>
</body>
</html>
```

For this example, we'll put together a simple toolbar with a button that opens and closes a nav menu. Let's drop the necessary elements into the `body`.

```html
<body>
  <header>
    <h1>Toolbar</h1>
    <button id="menu-btn">Menu</button>
  </header>
  <nav data-active="false">
    <ul>
      <li>News</li>
      <li>About</li>
      <li>Contact</li>
    </ul>
  </nav>
  <script></script>
</body>
```

Notice that we put an `id` attribute on our button so we can select it with confidence in our JavaScript and that we put a data attribute called `active` on our `nav` element.

Now let's add just a pinch of CSS to the page. In the HTML `head`:

```html
<style>
  header {
    background: #ccc;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
</style>
```

All we're doing here is setting a background for our header to make it look a little more like a toolbar, and using some flex rules to spread the `h1` and the `button` inside the `header` out to the edges.

Now let's think about what we want our button to do. Like the ever-present hamburger button, we just want it to open and close the nav menu. We'll use this behavior to take our data attribute knowledge for a spin.

So now let's add to our CSS:

```css
nav[data-active="false"] {
  display: none;
}
nav[data-active="true"] {
  display: block;
}
```

Now when the `active` data attribute is set to `"true"`, it will be displayed, but when it's set to `"false"`, it will not be displayed. With this added to the `style` tag, the `nav` element should disappear since we've written `data-active="false"`.

To make the button work, we'll add JavaScript to the `script` tag at the end of the HTML `body`. Let's write a function to handle the toggling, and then attach it to click events on the button.

```javascript
// First, grab our nav element
var nav = document.querySelector('nav');
// Then grab our menu button element
var menuButton = document.getElementById('menu-btn');

// Prepare a function to toggle the nav menu
var toggleNav = () => {
  // Check the data attribute to see if the menu is currently
  // active---notice that the data is a string
  var active = (nav.dataset.active === 'true');
  active = !active;
  nav.setAttribute('data-active', active);
}

// Listen for clicks on the menu button and
// handle clicks with the above toggleNav function
menuButton.addEventListener('click', toggleNav);
```

If we run our example code in a browser, the button should show and hide the nav menu as expected. One note about reading data attributes in JavaScript: they always arrive as strings. We may want to parse the data into an integer using `parseInt()`, translate it into a boolean as we do above with our `active` data attribute, or otherwise parse the data into a more useful type. Just remember that data stored in data attributes is always **treated as a string by HTML**.

# Wrap Up

One final note: working with data attributes won't be as fast as working with the values in a JavaScript object. Data attributes are powerful and in my opinion under-utilized, but like any other technique, remember that data attributes are just one tool on your toolbelt, and they should be a part of a larger weave of approaches that constitute a fully-featured solution. Try using data attributes to move quick hits of data around your code!