A better alternative to data-target attributes
And why using data attributes for JavaScript state setting and styling isn’t always the right choice.
If you’re a web developer, chances are you’ve seen or used a data-target attribute like this to control a widget in JavaScript:
In the above example, data-target specifies which element is the target to be controlled by the button — targeting the <div> with an ID of “myModal.”
But, there’s a much better way to accomplish the same goal!
Why a custom data-* attribute is inferior in this context
It may sound semantic with “target” being part of the attribute name, but it is not semantic. The W3C specification even says so:
Specifications intended for user agents must not define these attributes to have any meaningful values.
Plus, data-* attributes are intended to be used when there are no other alternatives, but a more appropriate attribute does exist.
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.
The better alternative in this context
In a previous post of mine, I discuss the value of using ARIA attributes in JavaScript and I illustrate how a developer can achieve many of the exact same goals with ARIA instead of classes or, in this case, data-* attributes.
In this context, the aria-controls attribute would be more appropriate. Not only is it far more semantic, but it adds necessary information for screen readers that wasn’t originally present in the above example. The code would look like this:
I think it’s safe to presume that almost every time you use data-target, you’re handling a button that controls another element. There may be other edge cases, but this context is most likely the large majority of use cases. Here, aria-controls is the better alternative.
If you find yourself using data-target in a context outside of a button controlling another element, then perhaps there’s an ARIA attribute that fits your use case, like aria-labelledby or aria-describedby. As a last resort — if there are no more appropriate attributes available — then use data-target. But, please don’t default to it.
Likely, there’s an ARIA attribute for that
Earnestly looking for more meaningful attributes other than simply defaulting to data-* attributes should be baked into your web development workflow. Taking time to consider how your application will be as bulletproof and as accessible as possible is just good programming.
Here are a few additional (of many more) ARIA attributes that provide similar benefits to aria-controls:
- aria-pressed=“true” — use this instead of an “active” class on buttons.
- aria-selected=“true” — use this instead of an “active” or “selected” class on tabs.
- aria-current=“true” — use this instead of an “active” class on pagination and menus.
- aria-expanded=“true” — use this instead of “open” class on accordions and other similar toggle-able widgets and their buttons.
Benefits to this method
Using ARIA attributes to style and set states in JavaScript will always have these benefits:
- As simple and as fast as the typical method of using data-* attributes (or applying/removing classes).
- Better accessibility built-in from the start.
- More semantic since ARIA attributes provide meaning.
The only downfall here is the learning curve involved in using ARIA properly — it’s yet another thing to learn in the world of web development. Back in the day, the frustration surrounding learning CSS instead of using tables for layout was the same. Defaulting to your current methods is always easier — change is harder. But, everyone benefits from changes like these in the long run.
Comments & feedback
As always, I am interested to hear everyone’s thoughts and feedback on replacing as many data-* attributes and CSS classes as possible with more semantic options, like ARIA attributes.
Note 1:
Obviously, if you’re using Bootstrap and you switched to aria-controls it wouldn’t work right out of the box. I’m simply using Bootstrap as an example here because the library is familiar with many developers.