Alex Kinnee

Using [data-action=""] selectors instead of class selectors when binding events in JavaScript

It’s still fairly common practice to target CSS classes in JavaScript. This is not optimal. Since we have the ability to add custom attributes to HTML elements, we should use those instead.

Say you want to open a contact popup when the user clicks a specific link on the page. Well, you might think it’s a good idea to do this:

<a class="contact-link">Contact</a>

var openContact = function() { /* Open the contact form */ };

Here’s the problem. Say you hire a new developer, or maybe you just haven’t looked at this code in a long time. There’s no obvious way to tell from looking at the HTML that there is an event listener on the contact-link class.

It’s also harder to search your codebase for a class name and find where the event listener is created. Even worse, what if your new frontend developer doesn’t realize that an event is bound to .contact-link and removes the class from the element, thinking that only the style will change?

Here’s a better way of doing this:

<a data-action="openContact">Contact</a>

var actions = {
    openContact: function() { /* Open the contact form */ }

Now, just by looking at this element, I can tell that it definitely does something. This is because of the word action.

Note: By prefixing data- onto any string, we can create as many custom, standards-compliant HTML attributes as we want.

Aren’t attribute selectors slower than class selectors?

It has been argued that attribute selectors are not as fast as class selectors in some (old) browsers, so we shouldn’t use them. I don’t really agree with that, because, while class selectors may be faster in IE8 (because IE8 can’t natively select data attributes), the speed difference is negligible. Unless you are querying the DOM hundreds or thousands of times per second (ಠ_ಠ), you won’t notice the difference. If you find you are doing that, you’re doing something wrong.

Can this help me write less code?

After posting this article on reddit, I received some great feedback.

The example below saves you from having to manually bind an event listener for each value that data-action might hold. It is a collaboration between /u/ChaseMoskal, /u/atticusw, Sébastien Lavoie, and myself.

var actions = {
    action1: function() {},
    action2: function() {}

$('body').on('click', '[data-action]', function() {
    var action = $(this).data('action');
    if (action in actions) {
        actions[action].apply(this, arguments);

12 Responses to Using [data-action=""] selectors instead of class selectors when binding events in JavaScript

  1. Alex says:

    This is definitely a great solution, I just worry about cross-browser (honestly, just IE6-8) compliance with data-role attributes. Sure things like html5shiv can handle that in theory, but in the wild things tend to go wrong often. If something happens and your shim doesn’t load…the entire DOM gets wrecked.

    • Alex Kinnee says:

      Actually the data attributes don’t require a shiv. HTML doesn’t break when you stick random attributes in the tag.

  2. Anonymous says:

    I am a front-end dev for a major retail site and I noticed that while performing maintenance tasks in our old code base I wasted an incredible amount of time tracking down crazy side effects that resulted when people attached event listeners using random selectors. The issues almost always manifest when unsuspecting junior devs modify seemingly innocuous html in an innocent way.

    To solve the problem noted in these observations I imposed this _exact_ convention when we began a responsive rewrite. Now that many portions of the responsive site have been released we are starting to see just how great this really is. I can tell you it’s a awesome idea and it scales extremely well. So far it has effectively eliminated side-effects of html rewrites and has given us the ability to quickly implement all of the crazy business requirements that a retail shop imposes on us devs with a much greater level of confidence that we aren’t breaking something.

    • Alex Kinnee says:

      Because you can only have one onclick handler, and the onclick handler can only access publicly accessible functions.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>