I often see ID attributes in HTML for styling elements, attaching JavaScript behaviours, and even using it in tests. Over time, I’ve found that ID’s may not be the best choice for any of these. I learned a few things.
In this article:
It’s possible to have more than one of the same ID in a page. Try this: when querySelectorAll
is used with an ID selector, will it return one result, or multiple results?
id
s are unique. Reality: multiple elements can have the same ID.If an element has an ID, that ID will be a global variable stored in window
.
window.drawer
.submitform
is automatically available in JavaScript.ID’s can cause confusion in CSS specificity. When ID’s are used for styling, it will have a side effect of increasing the specificity of the CSS rules. Let’s start with a simple HTML document with ID’s and classes:
color: white
rule doesn't seem to work in this example. Try this in the Codepen demo.#register-page a
) takes precedence over the second selector (.register-actions a
) because it uses an ID. As a result, the color doesn't turn to white.ID’s in JavaScript can be deceiving. Behaviour is sometimes attached to ID selectors that pick out a specific element. There are some caveats in this approach:
Overloaded semantics. Some projects use ID selectors (eg, #submit-form
) to signify style (CSS), behaviour (JavaScript) and semantics (Capybara tests). It’s overloaded, and it’d be hard to disconnect one from the other, such as if you want the same behaviour without the styling.
Difficult to test. It can be a bit awkward to test, possibly needing a mock #submit-form
element for it.
#submit-form
ID used for styling, adding behaviours, or test targets? Often: maybe all of the above.If ID’s are used in this way, consider attaching JavaScript behaviours to a data attribute. In the example above, there’s no easy way to attach this same generic behaviour to multiple forms. Instead of querying by ID, we can refactor the above to target a data attribute.
data-disable-on-submit
attribute can be added to any form and for it to pick up the behaviour.There are other ways to refer to elements in tests rather than ID’s. One common convention in JavaScript testing is to prefer to choose tests in this order:
For targeting elements in tests, consider querying using:
[role]
attribute[alt]
text (for images)[title]
text[data-testid]
attributeDespite all these, ID’s are still useful in a number of cases.
for
and aria-labelledby
.introduction
, lets the link scroll to where the content is.for
and aria-labelledby
uses ID's to refer to another element.Using ID attributes in HTML for styling elements, attaching JavaScript behaviors, and testing may not be the best choice. When it seems like using an ID is the best solution, it may be good to consider using alternative methods.
I found these to be helpful in untangling tests and JavaScript behaviours. Let me know how it work out for you in the comments below!
I am a web developer helping make the world a better place through JavaScript, Ruby, and UI design. I write articles like these often. If you'd like to stay in touch, subscribe to my list.