Custom attributes - Yea or nay? Custom attributes - Yea or nay? javascript javascript

Custom attributes - Yea or nay?


HTML 5 explicitly allows custom attributes that begin with data. So, for example, <p data-date-changed="Jan 24 5:23 p.m.">Hello</p> is valid. Since it's officially supported by a standard, I think this is the best option for custom attributes. And it doesn't require you to overload other attributes with hacks, so your HTML can stay semantic.

Source: http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes


Here's a technique I've been using recently:

<div id="someelement">    <!-- {        someRandomData: {a:1,b:2},        someString: "Foo"    } -->    <div>... other regular content...</div></div>

The comment-object ties to the parent element (i.e. #someelement).

Here's the parser: http://pastie.org/511358

To get the data for any particular element simply call parseData with a reference to that element passed as the only argument:

var myElem = document.getElementById('someelement');var data = parseData( myElem );data.someRandomData.a; // <= Access the object staight away

It can be more succinct than that:

<li id="foo">    <!--{specialID:245}-->    ... content ...</li>

Access it:

parseData( document.getElementById('foo') ).specialID; // <= 245

The only disadvantage of using this is that it cannot be used with self-closing elements (e.g. <img/>), since the comments must be within the element to be considered as that element's data.


EDIT:

Notable benefits of this technique:

  • Easy to implement
  • Does not invalidate HTML/XHTML
  • Easy to use/understand (basic JSON notation)
  • Unobtrusive and semantically cleaner than most alternatives

Here's the parser code (copied from the http://pastie.org/511358 hyperlink above, in case it ever becomes unavailable on pastie.org):

var parseData = (function(){    var getAllComments = function(context) {            var ret = [],                node = context.firstChild;            if (!node) { return ret; }            do {                if (node.nodeType === 8) {                    ret[ret.length] = node;                }                if (node.nodeType === 1) {                    ret = ret.concat( getAllComments(node) );                }            } while( node = node.nextSibling );            return ret;        },        cache = [0],        expando = 'data' + +new Date(),        data = function(node) {            var cacheIndex = node[expando],                nextCacheIndex = cache.length;            if(!cacheIndex) {                cacheIndex = node[expando] = nextCacheIndex;                cache[cacheIndex] = {};            }            return cache[cacheIndex];        };    return function(context) {        context = context || document.documentElement;        if ( data(context) && data(context).commentJSON ) {            return data(context).commentJSON;        }        var comments = getAllComments(context),            len = comments.length,            comment, cData;        while (len--) {            comment = comments[len];            cData = comment.data.replace(/\n|\r\n/g, '');            if ( /^\s*?\{.+\}\s*?$/.test(cData) ) {                try {                    data(comment.parentNode).commentJSON =                        (new Function('return ' + cData + ';'))();                } catch(e) {}            }        }        return data(context).commentJSON || true;    };})();


You can create any attribute if you specify a schema for your page.

For example:

Addthis

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:addthis="http://www.addthis.com/help/api-spec">...<a addthis:title="" addthis:url="" ...>

Facebook (even tags)

<html xmlns:og="http://opengraphprotocol.org/schema/" xmlns:fb="http://www.facebook.com/2008/fbml">...<fb:like href="http://developers.facebook.com/" width="450" height="80"/>