Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML5

XHTML Alternative to HTML5 Data Attributes

4.00/5 (4 votes)
1 Feb 2011CPOL2 min read 31.1K   102  
Use CSS Selectors as lightweight key value pairs; automatically bound to elements at runtime using the bindCssData method.

Introduction

I tend to write my own cross browser UI components and always strive to reduce the number of elements rendered in a page whilst also ensuring the mark-up validates. In situations where I need a key value pair but do not want to insert hidden fields, I use a custom CSS selector such as:

XML
<div id="mydiv" class="data-usedialogs-true">

prefix-key-value

I then have a script that executes when the page loads and goes through all (or selected) elements extracting the key value pairs and binding them to the actual element within the DOM.

This allows me to read/test the value using JavaScript without any manual parsing:

JavaScript
var mydiv = document.getElementById("mydiv");
if (mydiv.prefix.property=="true") 
{
    // do something...
}

This method is my W3C compliant (pre HTML5) alternative to the new HTML5 data attribute, whereby you can add custom data attributes to elements, e.g.:

XML
<div id="mydiv" data-usedialogs="true">

The good thing about this method is you can change the attribute, so you could have:

XML
<div id="mydiv" class="settings-autohide-true">

resulting in:

JavaScript
var mydiv = document.getElementById("mydiv");
if (mydiv.settings.autohide=="true")
{
    // do something...
}

How does the script work?

When the script executes, it looks through the DOM for all elements with a class name matching the regular expression prefix-[A-Za-z0-9]{1,}- [A-Za-z0-9]{1,}. Once it finds an element, it then creates a custom attribute on that element and assigns an array containing the keys and values found within the matching selector(s).

This means you can have multiple key value pairs within the same element:

XML
<div id="mydiv" class="data-usedialogs-true data-autohide-true">

Allowing you to read the values back in JavaScript as:

JavaScript
var mydiv = document.getElementById("mydiv");
if (mydiv.data.usedialogs=="true")
{
    // do something...
}

and:

JavaScript
var mydiv = document.getElementById("mydiv");
if (mydiv.data.autohide=="true")
{
    // do something...
}

The script

JavaScript
//
// turns custom class names into key/value expando properties
//
// css class data-title-hello can be retrieved using element.data.title
//
function bindCssData(t /*tagName*/, p /*prefix*/)
{
    p = p || "data";
    t = t || "*";
    var els = document.getElementsByTagName(t);
    var reg = new RegExp("^(" + p + ")-([A-Z0-9]{1,})-([A-Z0-9]{1,})$", "i");
    for (var i=0, l=els.length; i<l; i++)
    {
        var cssNames = (els[i].className != "") ? 
                           new String(els[i].className).split(' ') : [];
        if (cssNames.length<=0) continue;
        for (var ii=0, ll=cssNames.length; ii<ll; ii++)
        {
            var m = reg.exec(cssNames[ii]);
            if (m && m.length >= 2) {
                els[i][p] = els[i][p] || new Array();
                els[i][p][m[2]] = m[3];
            }
        }
    }
}

To use the script, call bindCssData() from within your window.onload function. If you do not pass any parameters to the function, it will parse all elements looking for a prefix of data. To make this faster, consider calling the function with only the element types (tagName) you want to affect:

JavaScript
bindCssData("span");

or

JavaScript
bindCssData("span", "settings");

Anticipated backlash -> Auto response

Of course, there will be many designers/developers out there that will disagree with the concept of using CSS selectors to carry data to client side scripts. However, in my defense and with progressive enhancement in mind, this is the cleanest solution I could come up with without inserting unnecessary bloat into the page. In addition, the ability to define your own prefix reduces the potential of a conflict with actual page styles.

For example, you could use an unnatural CSS selector such as __cssdata-key-value.

Feedback

I am always stupidly busy and don't get much time to knock-up these articles so there might be areas lacking explanation. If you feel I need to expand/correct anything, please leave a comment and I will update it as soon as I can.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)