Put that data-* attribute away, son...You might hurt someone
HTML 5 data-* attributes allow us to add custom attributes to elements as long as they are prefixed with ‘data-’ and since this was first discussed on John Resig’s blog I’ve been interested in how people will use and abuse this feature. I greeted the feature with mixed feelings. It’s definitely a simple way to enrich the semantic value of HTML pages as well as helping to improve some of the more toxic parts of Microformats. XML namespaces are definitely a more complete solution but this is a simple and immeadiately adoptable means to add invisible semantic data to HTML documents.
By all means, use data-* attributes to add semantically valuable data to your HTML but if you are just using it to prop up a script you are writing think again.
If you’ve not already watched it go now and watch Yehuda’s Screencast on evented programming with jQuery. The ideas in here represent a massive progression in client-side scripting. It’s nothing short of essential viewing. However, it also happens to be the latest example I’ve come across of needless use of data-* attributes and, while not wanting to take away from how progressive and clever the content is as a whole, I feel the need to use it as my counter-example for this article.
In the screencast, Yehuda is creating a tab interface. The markup he proposes is something like this:
<ul class="tabs"> <li data-content="first">First</li> <li data-content="second">Second</li> <li data-content="third">Third</li> </ul> <div class="pane" id="first">Some content</div> <div class="pane" id="second">Some content</div> <div class="pane" id="third" class="selected">Some content</div>
<ul class="section-nav"> <li><a href="#first">First</a></li> <li><a href="#second">Second</a></li> <li><a href="#third">Third</a></li> </ul> <div class="section" id="first">Some content</div> <div class="section" id="second">Some content</div> <div class="section" id="third">Some content</div>
With this markup as a base it’s then just as trivial to hook in the script but instead of interogatting data-content we just look at the anchor of the link. Because we are now using anchors, users can deep link into a particular tab, it would be trivial to support the back button and assistive technologies will make better sense of it, amoung other things.
Leave Yehuda Alone!
Of course, I’m picking apart what was a very simple and purposefully contrived example, but as usage of data-* attributes picks up, it’s important to not abuse this facility and to continue find as many semantic hooks for your scripts as possible. It may now be a “standard” but it doesn’t mean that its a good solution. When looking for hooks for my scripts, this is the process I follow:
2. Write your script to take advantage of the semantics your HTML document has to offer. This will get you a long way in many cases, however, you may well find that there is still configuration information you need to pass into your script. Rather than turn to data-* attributes its best to consider inferring this information via context in the same way that CSS does. This way you can assert things like “all <input>s with type ‘slider’ and a class ‘day’ have a min of 1 and a max of 31” then you can change this in one place rather than visiting each element’s data-* attributes individually. Read this article for more detail on how to do that. We don’t need to change the heading colour in every single heading element in our site now we have CSS, let’s not start doing that kind of thing again now we have data-* attributes.
I welcome the data-* attribute. It’s a simple and immediately useful method to add custom semantic data to HTML documents. Just avoid using it to litter implementation-specific crap into your documents :)
24 Comments (Closed)
I have seen some people use data-* to have some data attached to the node.
jQuery metadata plugin allows one to embed data in many other ways without resorting to having data-*. Checkout this excellent plugin at http://plugins.jquery.com/project/metadata .
Neeraj at 27.01.10 / 15PM
I think the markup you suggest for the Tab control is spot-on and makes semantic sense.
As far as good use cases go, I think there are certain cases where it makes sense. For instance, showing a human friendly Date/Time combo, but embedding the timestamp in a `data-time=”...”` attribute for easy JS parsing and use.
Good points and thanks for sharing!
Douglas Neiner at 27.01.10 / 16PM
Exactly my thoughts while watching the presentation. Not to take away the main point of trying to think “what would the browser do” before coming up with your implementation, which I thought was a simple but powerful idea.
Ismael at 27.01.10 / 16PM
In cases like the tab navigation, I’ve also semi-abused the ‘rel’ attribute for data- element-like behavior. It’s not 100% correct, but the anchor markup looks like it would be harder when you need JS buttons to flip tabs in order. With sequential numbers in ‘rel’, it’s pretty straightforward to grab the current tab, increment the value and bring that content to the front.
Matt Jones at 27.01.10 / 16PM
Douglas: Agreed. I think data-* attributes would be good way to avoid the abbr pattern in Microformats. In that case you are adding a machine readable date to an element which isn’t implementation specific and does enrich the document semantically.
Ismael: I’d like to make clear that I really like the screencast as a whole. It just was the last thing I saw that demostrated what I wanted to talk about. Im sure Yehuda would have marked it up the other way but the markup was not central to what he was explaining so its easy to overlook.
Matt: Leave the rel attribute alone, you fiend!!!
Dan Webb at 27.01.10 / 17PM
Your core point is very much correct; that application creators should use the best available semantics for their scripting before extending it with embedded data. There is very much a danger that given a generic, script-centric mechanism like this people with poor awareness of document structure will just skip over the functionality of HTML to make their scripts work.
One correction: You cite microformats as a possible consumer of data-* attributes, that is incorrect. The data-* spec explicitly excludes using date-* attributes for organized, shared vocabularies, or for parsing by anything outside of the page context. The feature is explicitly for in-page functionality, not for sharing structured data.
Microdata is the part of HTML5 that would provide new syntax for microformat vocabularies, but of course the current state of the infighting means that has been taken out of the spec.
Concerning the abbr-pattern, an alternative, HTML4-valid solution—the value-class-pattern—was published last year.
Ben Ward at 27.01.10 / 20PM
Ben: Thanks. That’s really interesting. So it sounds like proposed usage of data-* attributes is almost exclusively what I would consider an abuse of the attribute. Hmrph. Off-hand, I can think of a few good uses for data-* within the scope of in-page functionality but there aren’t going to be many that couldn’t be achieved in a better way. It’s like a build your own semantically useless markup kit. data-animate-left=”5px”. Worse than I thought.
I’m obviously behind on Microformats. I’d not come across the value-class-pattern before. I’m glad a better solution exists for the pattern now.
Dan Webb at 27.01.10 / 21PM
Great read. I’m interested in your opinion of something like this:
<a href=”some_url” class=”popup” data-height=”460px” data-width=”600px” /> ...
Using the data attribute to hold the height and width info of the popup to create configurable html popups. This is somethign I’ve been advocating as a way to make it easier for designers to make popup windows happen without the need for onclicks containing the window.open stuff.
Or would you consider this to be an abuse too?
Brian Hogan at 28.01.10 / 06AM
This is a great article Dan, and one I find useful because it’s not just the old overcooked argument about semantic markup, but rather a pragmatic appeal to leverage existing standards where applicable. I think the main problem here is the divide between web designers and developers. Traditionally designers have been the ones raving about standards and semantic markup, largely because HTML and CSS were their bread and butter whereas back-end developers had to concern themselves with a much thicker stack thus where HTML is sometimes treated as icing rather than the foundational layer of the client-side.
The data attributes in HTML5 are a great feature that will inevitably see a lot of abuse as people figure it out. The carnage will be substantially less than the abuse of the
TABLEelement, but conceptually a similar pitfall.
div.star_ratingsand uses their
film_idsto load the logged-in user’s ratings dynamically.
The benefits here are huge. In essence the loading of a user’s star ratings is decoupled from the template hierarchy in which they appear. That may not sound like much, but in a standard Rails controller where the data is being loaded, it’s not necessarily straightforward to know what data some sub-template is going to need. This technique allows a template to specify that some data is needed, but the data is only lazily loaded by the client where it is easy to wrap up all the necessary data into one optimized request, even if they are generated by disparate partial templates that know nothing about each other. Once user-specific data is lazily loaded from standard markup then suddenly the entire page is naively cacheable leading to a several-orders-of-magnitude scalability improvement.
Gabe da Silveira at 28.01.10 / 07AM
Sounds like a simple argument.
You’re saying that data-* attributes are the style attributes of scripting. You can use inline styles, but any programmer worth his salt detaches completely into separate CSS files.
Separation of concerns and all that. Same deal.
Gabe makes a valid point though. Sometimes the data needs to be output into the page with the HTML. If that data can’t be semantically incorporated, then that’s when you dig out the data-* attributes.
It’s a niche case that excuses the invention, and will lead to some horrible markup crimes.
W3C should make a damn clear case about best practice right there in the spec.
Kenneth at 28.01.10 / 09AM
Gabe da Silveira at 28.01.10 / 17PM
@Brian: that belongs in a stylesheet. You never know which device will open that popup (iPhone, iPad, desktop browser) so you have to fine-tune its dimensions together with the rest of the layout.
Mislav at 28.01.10 / 18PM
@Gabe da Silveira
Dimensions for window.open() can be stored in the CSS? Explain how please. I’d love to see that. I could see that working for a div that opens as an overlay, but not for a new window.
Even still, I don’t trust mobile stylesheets (as the iPhone is just gonna use screen ones anyway) so I end up serving different views.
But very interested to know how you’d use CSS to solve this issue.
Brian Hogan at 28.01.10 / 20PM
Sorry, that was meant for @mislav . My mistake.
Brian Hogan at 28.01.10 / 20PM
Gabe da Silveira: What exactly is a good example of using the style attribute?
Dan Webb at 29.01.10 / 01AM
thx,dan for the good article will test this once. regards from cologne
Frank at 29.01.10 / 14PM
Hi, Dan! Really an usefully article. I hope you put more Articles like this. Interesting!
Thanks and many regards from Germany
Druckertinte at 29.01.10 / 21PM
Exactly how I feel. Too bad it appears Rails 3 “UJS” refactoring will be using these attributes. At least the last time I checked anyway.
cheapRoc at 30.01.10 / 17PM
Ugh, it seems like you missed the point even with my detailed explanation. I could sit down with you over coffee for an hour and explain the history behind this code and why it is the way it is, but that is immaterial. You claim that more semantic markup would “make all the difference” and “avoid the problems I had”, but you are fixated on minor markup details which actually have nothing to do with the custom attribute or the problems I was solving
The point is, where do we store the film_id? Do we try to shoehorn it into a standard “semantic” attribute somewhere, maybe parsing it out of an class like “film_xxxx” on an ancestor element or do we just use a custom attribute?
There are real benefits to custom attribute usage vs attempting to put it in a standardized HTML attribute for its own sake. I am saddened that I was unable to show the forest for the trees.
Gabe at 01.02.10 / 18PM
Gabe: Apologies for not being more specific. Hopefully this will explain what Im getting at.
I’d use either a select element containing values 1 to 5 or radio buttons. Depending on how the page was structured each rating could be its own form in which case you’d put the film_id either in a hidden field or as part of the form action, or you could put a form around the all the ratings and name select select boxes film[id] (where id is the film id).
Dan Webb at 02.02.10 / 02AM
In short, the most semantic way of modeling something in HTML isn’t better per se. If it makes things more complex it needs to be justified just like anything else.
Gabe da Silveira at 03.02.10 / 19PM
Hi Dan, we follow your blog on daily bases. This is a great article, and hope you will continue with good work. Best regards from ITS team. Thanks for making it easier for all of us to work and understand new stuff and improving our sites.
Infotech web design studio at 28.02.10 / 15PM
Thanks a lot for this informative article. regards
Josh at 27.03.10 / 18PM
Your Article are very informative and very interesting. I hope it´s going be a longer time ;)
Thanks again, Dan
Zahnimplantate at 09.04.10 / 05AM