If you are building an application with JavaScript on the front end you will probably need to hook your JS code to html elements in order to respond to events. This is very common when building apps with jQuery, Backbone, CanJS and the like. E.g.
javascript
$('.btn_view').click(...)
In this case the class btn_view
is the hook that JS uses for listening to or manipulating the DOM. The choice of what to use for these hooks may seem inconsequential at first but it is an important decisions that can aid a lot with the maitainability of your application.
So I want to share my conclusions on best practices for adding JS hook in DOM elements.
Note: This is not a big concern in Frameworks like Angular and Ember as they rarely rely on these kind of JS hooks to interactive with the DOM.
Note:: When I refer to components
in this post I am not talking about Web Compoments, but about reusable views that are added to the DOM, e.g. Backbone views.
IDs
The first obvious candidate is using an ID e.g. $('#btn_view')
. This is a very popular option, but it has a big drawback. IDs shouldn’t be repeated in a page, meaning that you can only have one of each. This hinders reusability of components. E.g. you cannot have multiple views of the same component in a page because they use the same IDs.
This might not seem like a problem at the beginning, but at some point you might want to include many of the same components in a page and you will regret using IDs.
So my rule is that IDs should only be used for elements that I am 100% certain will not be repeated, for example the site main navigation or generated IDs (See the bottom of this post).
Note: Web components get away with this restriction as the elements inside a component are encapsulated, so using IDs is a perfectly good approach when building web components.
Aria Roles
Aria roles are there to aid with accessibility of the page, it is a good practice to add them but don’t use them for JS hooks, that is not what they are for. And don’t invent roles that aren’t recognised, for more information see here
Data
Data attributes are meant to be used for adding any arbitrary data to your DOM, so on paper they are the best solution. e.g.
html
<a data-btn-view href="#">View</a>
js
$('[data-btn-view]').click(...);
This is not too bad if you don’t mind writing selectors like [data-btn-view]
. I however decided that it is ugly enough to not use data attributes for JS hooks. At least until libraries and frameworks add a more concise selector for data attributes.
Classes
Classes are the other popular choice. They are very concise e.g. $('.btn_view')
. But they have a big problem, they are mainly using for CSS styling. This make using classes very brittle. What happens when someone decides that this element should not have that style anymore? Your JS might suddenly stop working. This can be a subtle bug and really hard to spot.
Still classes are the easier option with less problems. To avoid issues in the future all you need is some naming conventions. Instead of hooking on classes used for CSS, add extra classes to your elements just for JS and name them in a special way that makes sense to your team. e.g.
html
<a class='_btn_view btn' href='#'>View</a>
js
$('._btn_view')
In this case I use the underscore (e.g. _btn_view
) to denote the fact that this is a class intended for hooking JS code onto the element. Everyone on the team will know that they shouldn’t remove or change that class in that element, every other class e.g. btn is fair game.
Another popular alternative is using js
at the front of the class e.g. js_btn_view
.
Generated IDs
If you need to have IDs in your components I prefer them to be auto-generated and only have one ID per component at the top level, e.g.
```html
Sam Sample
View```
Then I pass the generated ID to the JS view code.
Conclusion
So my best practices for adding JS hooks to the DOM are:
- Don’t use IDs, or only auto generate IDs on the top level of each component.
- Don’t use Aria roles for JS hooks
- Data attributes are good but ugly to work with
- Don’t use classes meant for styling
- Use classes named with a special convention e.g.
_btn_view
Do you have a best practice that works for you? Please let me know.