HTML5 Custom Data Attributes (data-*)

by .

Have you ever found yourself using element class names or rel attributes to store arbitrary snippets of metadata for the sole purpose of making your JavaScript simpler? If you have, then I have some exciting news for you! If you haven't and you're thinking, Wow, that's a great idea! I implore you to rid your mind of that thought immediately and continue reading.

Thanks to HTML5, we now have the ability to embed custom data attributes on all HTML elements. These new custom data attributes consist of two parts:

Attribute Name
The data attribute name must be at least one character long and must be prefixed with 'data-'. It should not contain any uppercase letters.
Attribute Value
The attribute value can be any string.

Using this syntax, we can add application data to our markup as shown below:

<ul id="vegetable-seeds">
  <li data-spacing="10cm" data-sowing-time="March to June">Carrots</li>
  <li data-spacing="30cm" data-sowing-time="February to March">Celery</li>
  <li data-spacing="3cm" data-sowing-time="March to September">Radishes</li>
</ul> 

We can now use this stored data in our site’s JavaScript to create a richer, more engaging user experience. Imagine that when a user clicks on a vegetable a new layer opens up in the browser displaying the additional seed spacing and sowing instructions. Thanks to the data- attributes we’ve added to our <li> elements, we can now display this information instantly without having to worry about making any Ajax calls and without having to make any server-side database queries.

Prefixing the custom attributes with data- ensures that they will be completely ignored by the user agent. As far as the browser and indeed the website’s end user are concerned, this data does not exist.

The spec says (emphasis ours):

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.

These attributes are not intended for use by software that is independent of the site that uses the attributes.

Every HTML element may have any number of custom data attributes specified, with any value.

W3C Specification

How can I use data attributes?

As custom data attributes are valid HTML5, they can be used in any browser that supports HTML5 doctypes. Thankfully, this is pretty much all of them. In addition to aiding backwards compatibility, this also ensures that custom data attributes will remain a scalable, cross-platform solution well into the future.

Now that we have a broad understanding of what data attributes are, let's take a look at how they can be used:

  • To store the initial height or opacity of an element which might be required in later JavaScript animation calculations
  • To store parameters for a Flash movie that’s loaded via JavaScript
  • To store custom web analytics tagging data as demonstrated by Jason Karns
  • To store data about the health, ammo, or lives of an element in a JavaScript game
  • To power accessible JavaScript <video> subtitles as demonstrated by Bruce Lawson

What shouldn’t I use data attributes for?

Although flexible, data attributes aren’t an appropriate solution for all problems.

  • Data attributes should not be used if there is a existing attribute or element which is more appropriate for storing your data. For example, date/time data should probably be presented semantically in a time element instead rather than stored in custom data attributes.
  • Custom data attributes are not intended to compete with microformats. It is clearly stated in the spec that the data is not intended to be publicly usable. External software should not interact with it. Marking up contact details or event details using custom data attributes would be wrong, unless of course it is only intended to be used by your own internal scripts.
  • The presence/absence of a particular data attribute should not be used as a CSS hook for any styling. Doing so would suggest that the data you are storing is of immediate importance to the user and should be marked up in a more semantic and accessible manner.

Using data- attributes with JavaScript

Now that we understand what custom data- attributes are and when we can use them, we should probably take a look at how we can interact with them using JavaScript.

If we wanted to retrieve or update these attributes using existing, native JavaScript, then we can do so using the getAttribute and setAttribute methods as shown below:

<div id='strawberry-plant' data-fruit='12'></div>

<script>
// 'Getting' data-attributes using getAttribute
var plant = document.getElementById('strawberry-plant');
var fruitCount = plant.getAttribute('data-fruit'); // fruitCount = '12'

// 'Setting' data-attributes using setAttribute
plant.setAttribute('data-fruit','7'); // Pesky birds
</script>

This method will work in all modern browsers, but it is not how data- attributes are intended to be used. The second (new and improved) way to achieve the same thing is by accessing an element’s dataset property. This dataset property — part of the new HTML5 JavaScript APIs — will return a DOMStringMap object of all the selected element's data- attributes. When using this approach, rather than using the full attribute name, you can ditch the data- prefix and refer to the custom data directly using the name you have assigned to it. Data attribute names which contain hyphens will be stripped of their hyphens and converted to CamelCase.

<div id='sunflower' data-leaves='47' data-plant-height='2.4m'></div>

<script>
// 'Getting' data-attributes using dataset 
var plant = document.getElementById('sunflower');
var leaves = plant.dataset.leaves; // leaves = 47;

// 'Setting' data-attributes using dataset
var tallness = plant.dataset.plantHeight; // 'plant-height' -> 'plantHeight'
plant.dataset.plantHeight = '3.6m';  // Cracking fertiliser
</script>

If, at some point in your script, a specific data- attribute becomes redundant and is no longer needed, it is also possible to completely remove that attribute from the DOM element by setting it to a value of null.

plant.dataset.leaves = null; // Caterpillars attack!

Unfortunately, the new dataset property has not yet been implemented in any browser, so in the meantime it’s best to use getAttribute and setAttribute as demonstrated earlier.

While developing your application, you may find it useful to be able to select elements based on the presence of — or indeed the specific values of — their custom data- attributes. This can be achieved quickly and easily using querySelectorAll as shown below:

// Select all elements with a 'data-flowering' attribute
document.querySelectorAll('[data-flowering]');

// Select all elements with red leaves
document.querySelectorAll('[data-foliage-colour="red"]');

A word of warning

As data attributes become more widely used, the potential for clashes in naming conventions becomes much greater. If you use an unimaginative attribute name such as data-height, then it is likely you will eventually come across a library or plugin that uses the same attribute name. Multiple scripts getting and setting a common data- attribute will probably cause chaos. In order to avoid this, I encourage people to choose a standard string (perhaps the site/plugin name) to prefix all their data- attributes — e.g. data-html5doctor-height or data-my-plugin-height.

Summary

Custom data- attributes are a great way to simplify the storage of application data in your web pages. Although you can’t utilise the new JavaScript APIs just yet, you can enjoy great success using getAttribute and setAttribute safe in the knowledge that they will work in all major browsers.

Homework

If you’re super keen to have a play with the new dataset property but disappointed that it hasn’t been implemented, fear not!, for there is a light at the end of the tunnel. You might be interested in looking at Dr Remy’s experimental code, which partially enables the dataset functionality in some browsers by editing the Element.prototype.

The code supports the retrieval of data- attributes in the latest versions of Firefox, Safari, Opera, and Chrome, but sadly will not work in any version of IE (since IE does not expose the Element object). This code also partially supports the setting of data attributes, but it will only store the new attribute values within the JavaScript and will not update the DOM element as a full, native implementation of the dataset property would. Although this code is mainly a proof of concept, it may be useful for mobile application or intranet development in closed environments where cross-browser (IE) compatibility is not an issue.

44 Responses on the article “HTML5 Custom Data Attributes (data-*)”

Brian LePore says

I firmly do not see why it is inappropriate to use custom data attributes for external applications provided that these external applications are not a requirement for viewing the page.

I am the author of a Firefox extension named Local Load. My extension allows developers to save bandwidth by using custom data attributes so that any user with the extension installed will instead load common JavaScript frameworks (e.g. jQuery, Prototype, etc.) from the hard drive rather than download them from the Web. If a user does not have the extension installed it will still load the framework from the Web, so there is nothing wrong there. The extension needs some form of additional markup to let it know that the script can be replaced, what the script is, and what the version is. The most appropriate mechanism of doing this is a custom data attribute. Just trying to guess what the version/script is could potentially break a ton of sites, so I would prefer to keep the script replacement feature an opt-in mechanism.

Julian Reschke says

Brian,

it is inappropriate because the spec says so.

The idea is that there are other extension points for your use case (such as custom attributes in other namespaces (in XHTML), RDFa, Microdata, Meta tags, whatnot).

If you believe that the restrictions for data-* should be lifted, or a similar mechanism allowing your use case should be added, you really should send feedback to the W3C HTML Working Group (for instance, through http://lists.w3.org/Archives/Public/public-html-comments/).

Julian

Scott Reynen says

I don’t understand why this article quotes the part of the spec saying data-* attributes are site-specific, and then gives a warning promoting namespacing. If you follow the spec, you’re creating all of the attribute names, so there’s zero reason for namespacing. That’s exactly why that’s in the spec.

Remy Sharp says

@Scott – the namespacing isn’t to create “site-specific” data attributes, but in-application namespacing.

For example (and IIRC the spec mentions this) a widget’s controls (like a tree view) may have data attributes, but the data attributes may have been created using a specific library, such as jQuery or Dojo – so to avoid data attribute collisions the application module may want to namespace it.

I can’t see where Chris referred to the data attribute being site-specific (but it’s late and I may have missed it).

There’s a lot of cases where you won’t want or need to use namespacing, but there are some cases where it makes sense. But since this just builds on existing content attributes rules – you’re free to decide how you use them.

jpvincent says

I’m using the data-* with getAttribute and setAttribute since I saw a post about that 2 years ago by Jon Resig, so I can confirm that this way of using it works for all browsers/platforms, starting with IE6.
I just hope that any browser implementing data-* natively won’t break the getAttribute method (it shouldnt but we never know)

From a performance point of view, accessing the DOM via getAttribute() is obviously slower than accessing to a JS variable, event stored in an array, so the use case you give of a JS game using it to store values will probably never happen : developers will use it to transmit info from server to client, but once the DOM has been harvested, it’s best to keep all the values in JS for quicker access

Chris Bewick says

@jpvincent – Yeah, I totally agree with you.

I guess the initial health and ammo data could be stored in a database and using a data-attribute would be a valid mechanism to transfer this information to the game’s javascript. But once this initialisation task is complete there is very little point in continuing to make costly DOM updates with the latest health/ammo stats.

Thanks for your comment.

pengkai says

it’s really useful to app. with more info.

skippy says

Or ya’ know you could try to design a clean separation of model and view layers…..

Leevi Graham says

Your article mentions that you shouldn’t use data-* for CSS hooks. What if the data-* attribute was used in the JS but you also wanted to apply styles to it. Wouldn’t it make sense to target the attribute rather than add a secondary class.

Take this form for example:

<form>
<div data-field_type="text">
<label>Title <em>*is required</em></label>
<div class="note">
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>
</div>
<input type="text" />
</div>
</form>

data-field_type=”text” could be used for both validation and styling layout.

mattcoz says

Pretty cool feature, although no browsers support it yet. This little bit of code works to add support for the dataset property to any browser that supports __defineGetter__. I wrote it before I realized you linked some code that does pretty much the same thing. My code, on the other hand, has support for actually udpating the attribute values, but it does not support adding new attributes.

Element.prototype.__defineGetter__(‘dataset’, function(){
var dataset = {};
for (var i=0, l=this.attributes.length; i<l; i++) {
var attr = this.attributes[i];
if (attr.name && attr.name.indexOf('data-') == 0) {
var el = this, name = new String(attr.name), key = name.substring(5).replace(/-([a-z])/ig, function (a, b) { return b.toUpperCase(); });
dataset.__defineGetter__(key, function(){ return el.getAttribute(name); });
dataset.__defineSetter__(key, function(value){ el.setAttribute(name, value); });
}
}
return dataset;
});

Harm says

Would these attributes work in the new Internet Explorer 9?

David R says

The data-* certainly will be useful, but that carrot example isn’t a great example. You would use the data in data-* attributes for, not for display of content. As you say, “It is clearly stated in the spec that the data is not intended to be publicly usable”

Instead of this:
<li data-spacing="10cm" data-sowing-time="March to June">Carrots</li>

You should include the content in actual html text, not in your attributes. That way your data is search engine indexed, accessible to machines in a readable format, etc. If I got the gt and lt right, it’d be something like:

<li">Carrots<span class="hidden">Spacing: 10cm. Sowing time: March to June</span></li>

Eric Leads says

My take is that if you’re creating classes that will never be styled, or storing variables in hidden form fields that never get read from on the server, those are both good use cases for the data- attribute.

However, you should ask yourself, “will I ever want to style this info or create any user feedback based on this data?”

If the answer is yes, then data- is the wrong approach.

Conrad Damon says

What about expando properties? Data attributes strike me as a namespaced (with “data-”) hash of expando properties, with the added dataset convenience. How do the following compare?

plant.setAttribute(‘data-fruit’,’7′);

plant.fruit = 7;

In general I’ve just stored element-related data in memory in a hash or object that can be retrieved based on the element’s ID.

Matt says

I’ve found a case where I feel using the data-* attributes for CSS hooks is valid. Feedback is, of course, welcome.

I have an HTML table of data that can be sorted, ascending and descending, with AJAX by clicking on the column headers. I opted to use a data-sort-dir=”asc” attribute on the column header to not only tell the AJAX call which direction to sort the request, but also to create an arrow next to the column header indicating which direction the arrow points.


a[data-sort-dir="asc"] {
/* Show the ascending arrow */
}

a[data-sort-dir="desc"] {
/* Show the descending arrow */
}

When a column header is clicked, the data-sort-dir attribute is updated or moved to properly reflect which direction is being sorted.

I also agree that the carrot example was a poor example since you’re storing data to display to the user in another method which was stated to be against the spec. In that case, the hidden element option David R posed in the comments or using the title attribute probably would’ve been better.

Andres says

If i’m using ARIA, should I add the attribute as “data-role” or just “role”????

are both valid?

Chris Bewick says

@Andres – data-* is only for storing data which is to be used within your own website. As the primary purpose of ARIA roles is to communicate additional page structure to the browser/screenreader this would not be an appropriate time to use them. Stick with role=”main”.

kevin says

I use the data attributes a lot for jQuery apps. This attribute is for you to store private data for your application. If you are planning to have data understood by the search engines, you could use microdata which is more semantic.

ryanve says

Would data attributes be appropriate for something like switching an “’s src attribute between a hi-res and lo-res version (for better performing responsive design)? (Something like this)

Also what is the best way to test support for this?

BJ says

“Thanks to HTML5, we now have the ability to embed custom data attributes on all HTML elements[!!11!!1!1!]“

Wow, like expando properties avail since IE4? Thanks HTML5, you’re the best!

OK, assuming “dataset” provides a collection of values across multiple elements, that’s kind of useful (although already trivial via jQuery) .. but this article smacks of feature amnesia.

Jonathon says

surely styling to data-* makes sense in a data rich web app rather than bloating the class attribute?

in pseudo code interfacing with the data as a user interface: remove class X
add class Y

as a feedback on and as a consequence of a user action

vs change data-* to Y

not that looking at the underlying DOM is critical for the enduser, but filling class with non-hierarchical data FOR THE SAKE OF STYLING seems more wrong than styling to data also being held???

Gleenk says

But what are the support for html5 doctype?

Mag Leahy says

I like this a lot!

ryanve says

Have any browsers implemented the dataset deletion algorithm? Doing `plant.dataset.leaves = null` in Chrome it does not remove the attribute. It converts it to the text ‘null’. Is that in the spec?

jason says

Well it appears that facebook is using the data- tag for a while now… so I would say it widely accepted by most browsers…

ryanve says

@ryanve To remove data attributes, `delete plant.dataset.leaves` works.

ASKWHYWEB Solutions says

Nice article, perhaps it needs a slight modification to be understandable by some of the very fresh and new entries into JS and HTML5.

Overall, Very good effort. I like it.
Thanks

putri says

Thank you for posting this topic, I really need this as reference.

Putri says

I am newbie in here, but I get understand about HTML5 attribute from your explanation. Thank you, I like to come in here again and again

Rudy Chou says

Very nice article write up on the HTML5 data attribute. This gave me a good overview of the possibilities and things to come in the specs.

As far as how I’ll be using it, I’m thinking using it for analytics or event triggers for js.

Thanks.

muhammed basil says

Hi
I’ve found an issue with the data attribute. If we put long number as value of data attribute ( data-longnumber = 111111111111111222222222222222222222233333333333333333333333333333333333333333333333333331111111111111111122222222222222222222222222222222222222222222222222222222211111111111 )
and when fetched using jquery
$(‘div’).data(‘longnumber’)
it returns an exponential value ( 1.1111111111111112e+209)
What will be the issue?
Is there any solution for this?

Thanks

Vipul S. Chawathe says

Is there any guideline for consuming RDFa in XHTML5?
As per my limited understanding, DOCTYPE is ignored within these files, version attribute is deprecated. I’m using <link rel="profile" href="http://www.w3.org/1999/xhtml/vocab"/> within head tag.
The property attribute is used by creative commons license I’m placing at the file’s footer.

Steve Paesani says

Since we’re talking scripting and thus the DOM
setAttribute has been specified as capable since DOM Core 1.0 to set user defined attributes and there are no implementation issues.

Those of us however that script xml documents, including htmlN.. documents, usually use an object reference to elements and store user defined variables there as they are faster to access and address any scripting need:

var a=elobj['elementid'].user_defined_attribute;

is faster than

var a=element.getAttribute(user_defined_attribute);

and can address any scripting need that data-* or any other markup language scripting feature pretends to introduce or provide.

DAL says

Hello all

I am a professionnal programmer and i am now switching to html5 and App building…

So far so good, but i have one small problem i cannot seems to be able to solve.

I want to simply:

read a remote text file on my server
read the file by lines
localstore by pairs

period… simple right? well, i found about 20 different answers online, none works.

Where can i find a REAL answer?

How does game makers do to upload a dictionnary of words for example in a mobile device in pairs?

Thanks

Ventura Rodríguez says

I’m starting with HTML5 and the truth is I did not know this label. Apparently it is very últil, the study it thoroughly to use it in my next projects.

Pierre-Adrien says

I noticed this kind of fields when dealing with Rails projects, but did not find time to investigate this at the moment. I’m glad I did today, thanks for this really helpful article.

programaths says

@BJ,

Expando properties and “data-*” attributes aren’t quite the same thing.

if someone write :

<div src="image.png"></div>

How can the validators/engines knows that the author didn’t want to write

<img src="image.png">

With “data-*” attributes, it’s possible to know the Author’s intention.

If someone write:

<div data-src="image.png"></div>

He probably meant it.

That’s how Microsoft got wrong and continue to be.
Admitingly, expando properties were a good idea (On the implemenation side, it means LESS validation required) but not as good than requiring “data-” prefix.

Also, imagine than in HTML6, divs can take a “src” attribute to load asynchronous content. (Eg. you are rendering something complex so you want the user to not wait in front of a blank page)
Without the “data-” attribute, you can’t simply change your doctype to “html6″, it makes migration harder.

With the “data-*” attribute you are certain that your html website won’t be broken because the spec did add a new attribute.

Ben Racicot says

Can we use the new dataset selector yet?!

jhonatan says

hello, I’m using custom data attribute to loading posts content with JavaScript without an Ajax query.

EX:


<a href="#" rel="nofollow">load content</a>

am i wrong if I put html content in the data attribute?? please I have this doubt

could it be that a SEO trouble??

thanks!

gautham says

isn’t using/storing data values in html markup a bad design?
so if we consider things like single responsibility principle(not like a design pattern that it is,but like a word of wisdom),aren’t we messing up with what HTML is designed to do???

Join the discussion.

Some HTML is ok

You can use these tags:
<a href="" title="">
<abbr title="">
<b>
<blockquote cite="">
<cite>
<del datetime="">
<em>
<i>
<q cite="">
<strong>

You can also use <code>, and remember to use &lt; and &gt; for brackets.