How to Build Better UX with HTML5 Data-* Attributes

Have you ever wanted to add custom data to a particular HTML element in order to later access it with JavaScript? Before HTML5 appeared on the market, storing custom data associated with the DOM was a real fuss, and developers had to use all kinds of nasty hacks, such as introducing non-standard attributes or using the obsolete setUserData() method to work around the problem.

Luckily you don’t have to do so any more, as HTML5 has introduced new global data-* attributes that make it possible to embed extra information on any HTML elements. The new data-* attributes make HTML more extensible, therefore enable you to build more complex apps, and create a more sophisticated user experience without having to use resource-intensive techniques such as Ajax-calls, or server-side database queries.

Browser support of the new global attributes is relatively good, as they’re supported by all modern browsers (IE8-10 partially supports them).

Data Attributes

Syntax of the data-* Attributes

The syntax of the new data-* attributes is similar to that of the aria-prefixed attributes. You can insert any lowercase string in place of the * sign. You also need to assign a value to each attribute in the form of a string.

Let’s say you want to create an About Us page, and store the name of the department where each employee works. You don’t have to do anything else apart from adding the data-department custom attribute to the appropriate HTML element in the following way:

<ul>
	<li data-department="Marketing">
		John Doe
	</li>
	<li data-department="IT">
		Jane Doe
	</li>
</ul>

Custom data-* attributes are global, just like the class and id attributes, so you can use them on every HTML element. You can also add as many data-* attributes to an HTML tag as you want. In the example above, for instance you can introduce a new custom attribute called data-user to store employee usernames.

<ul>
	<li id="john" class="employee" data-department="Marketing" 
	data-user="johndoe">
		John Doe
	</li>
	<li id="jane" class="employee" data-department="IT" 
	data-user="janedoe">
		Jane Doe
	</li>
</ul>

As a general rule, if you want to add your own custom attribute to an HTML element, you always have to prefix it with the data- string. Likewise, when you see a data-prefixed attribute in someone else’s code, you can know for sure that it’s a custom attribute introduced by the author.

When to Use and When Not to Use Custom Attributes

W3C defines custom data-* attributes like so:

“Custom data attributes are intended to store custom data private to the page or application, for which there are no more appropriate attributes or elements.”

It’s worth to consider using data-* attributes when you can’t find any other semantic attributes for the data you want to store.

It’s not the best idea to use them solely for styling purposes, as for that you can choose from the class and the style attributes. If you want to store a data type for which HTML5 has a semantic attribute, such as the datetime attribute for the <time> element, use that instead of the data-prefixed attribute.

It’s important to note that data-* attributes hold data that’s private to the page or the application, which means that they will be ignored by user agents, such as search engine bots and external applications. Data-prefixed attributes can solely be accessed by the code running on the site that hosts the HTML.

Custom data-* attributes are extensively used by frontend frameworks, such as Bootstrap and Zurb Foundation, as well. The good news is that you don’t necessarily need to know how to write JavaScript if you want to use data-prefixed attributes as a part of a framework, as you only need to add them to the HTML code to trigger a functionality of a prewritten JavaScript plugin.

The code snippet below adds a tooltip on the left to a button in Bootstrap by making use of the data-toggle and the data-placement custom attributes, and assigning appropriate values to them.

<button type="button" class="btn btn-default" data-toggle="tooltip" 
data-placement="left" title="Tooltip on left">
	Tooltip on left
</button>

Target data-* Attributes with CSS

Although it’s not recommended to use data-* attributes only for styling purposes, you can select the HTML elements they belong to with the help of general attribute selectors. If you want to select each element that has a certain data-prefixed attribute, use this syntax in your CSS:

li[data-user] {
	color: blue;
}

Note that it’s not the usernames that will be displayed in blue in the code snippet above – after all the data stored in the custom attributes is not visible – but the names of employees contained in the <li> elements (in the example “John Doe” and “Jane Doe”).

If you only want to select elements in which a data-prefixed attribute takes a certain value, this is the syntax to use:

li[data-department="IT"] {
	border: solid blue 1px;
}

You can use all the more complicated CSS attribute selectors, such as the general sibling combinator selector ([data-value~="foo"]) or the wildcard selector ([data-value*="foo"]), with data-prefixed attributes as well.

Access data-* Attributes with JavaScript

You can access the data stored in the custom data-* attributes with JavaScript by using either the dataset property, or jQuery’s data() method.

Vanilla JavaScript

The dataset property is the property of the HTMLElement interface, that means you can use it on any HTML tag. The dataset property gives access to all custom data-* attributes of the given HTML element. The attributes are returned as a DOMStringMap object that contains one entry for each data-* attribute.

In our About Us page example you can easily check the custom attributes “Jane Doe” has by using the dataset property in the following way:

var jane = document.getElementById("jane"); 
console.log(jane.dataset);
// DOMStringMap { user: "janedoe", department: "IT" }

You can see that in the returned DOMStringMap object the data- prefixes are removed from the names of the attributes (user instead of data-user, and department instead of data-department). You need to use the attributes in the same format if you only want to access the value of a certain data-prefixed attribute (instead of the list of all custom attributes like in the code snippet above).

You can retrieve the value of a specific data-* attribute as a property of the dataset property. As I mentioned before, you need to omit the data- prefix from the name of the property, so if you want to access the value of Jane’s data-user attribute, you can do it this way:

var jane = document.getElementById("jane"); 
console.log(jane.dataset.user)
// janedoe

jQuery’s data() method

The data() jQuery method makes it possible to get the value of a data-prefixed attribute. Here you also have to omit the data- prefix from the name of the attribute to access it properly. In our example, you can display an alert message with the name of the department where “Jane” works with the following code:

$("#jane").hover( function() {
	var department = $("#jane").data("department");
	alert(department);
});

The data() method needs to be used carefully, as it doesn’t only act as a means to get the value of a data-prefixed attribute, but also to attach data to a DOM element in the following way:

var town = $("#jane").data("town", "New York");

The extra data you attach with jQuery’s data() method obviously won’t appear in the HTML code as a new data-* attribute, so if both techniques are used at the same time, the given HTML element will store two sets of data, one with HTML and the other with jQuery.

In our example “Jane” got a new custom data ("town") with jQuery, but this new key-value pair won’t appear in HTML as a new data-town attribute. Storing data in two different ways is not the best practice to say the least, so only use one of the two methods at once.

Accessibility and data-* Attributes

As the data held in custom data-* attributes is private, assistive technologies may not be able to access it. If you want to keep your content accessible for disabled users, it’s not recommended to store content that can be important for users this way.