What the ID attribute is REALLY for
— 6 minutes to read
This post takes a look at how and when to use the HTML
ID attribute, along with related accessibility considerations. I hope it's helpful!
When we talk of IDs, really we're looking at the attribute value, as demonstrated here with "uniqueHeadingId" in this example:
This heading has an ID attribute.
A few quick caveats about this super-important little attribute...
You don't need IDs on everything! Only add them when you need to (see uses below).
IDs must not contain spaces or special characters. That's invalid HTML.
Every ID value on a page must be unique. If you remember nothing else from this post, please remember that!
This last point sounds easy to achieve but can be very tricky in practice. For example, consider component-based systems, (especially on CMS-powered sites) where you may not know exactly where or how frequently a component might be used on a page.
Or course if you know an element will only ever occur once on a page, it's fine to hard-code an ID. For example, a menu or theme toggle located in the site header is likely to be static, so can have a hard-coded ID value.
Just be warned — In other scenarios, you may need to work harder for those unique IDs!
📖 Further reading on unique IDs: look up 'GUIDs'
Think of an ID an anchor point in the HTML. That's it's primary job! But there are a number of ways it can be used:
- As a CSS selector
- As a JS selector
- As an anchor for navigation
- As an anchor for other HTML attributes (to programmatically link elements to each other)
Let's look at each one in turn with some practical examples.
Just because you can use ID attributes as style selectors, it doesn't mean you should. Example:
<!-- HTML -->
/* CSS */
⚠️ This is not recommended!
ID selectors have a higher specificity in CSS than classes. Generally, you want to keep CSS specificity as small/low/flat as possible. Anything that increases specificity is therefore undesirable.
You may think, "It's fine! I know this element will only ever be used this once and will never need its styles changing." But that brings up a new negative... Would other developers think the same? (including your future self!)
I've seen IDs change a LOT while working on various code bases over the years. Either the ID names weren't clear enough, or a new system gets introduced to make sure they're always unique, or they get changed for some other reason. If (when) that happens, the styles suddenly break. And no one ever expects changing IDs to have an impact on styling because it's well-established that styling hooks should be on classes, not IDs.
This isn't as bad and is certainly a more common practice you'll encounter. For example:
/* JS */
const myButton = document.querySelector('#super-cool-id');
// or... (a marginally less performant version)
const myOtherButton = document.getElementByID('cool-id');
⚠️ In my opinion, using IDs as JS selectors is still not a great idea!
The problems come
- When IDs have to be programmatically generated to be unique. Suddenly your nice code standard can't be used any more and you'll have to lean on a class or element selector instead.
- When there is a lack of clarity (How would a dev looking at the HTML know that an ID is important for JS functionality?)
- With lack of consistency. Usually, when people use IDs in JS, it's not an exclusive pattern. I often see a mixture of ID and element and class selectors, which can only lead to confusion and breakage as a team grows.
A bonus of not using IDs as JS selectors is that they're left alone for their real purpose... anchoring.
HTML is pretty beautiful. Any time you use an ID attribute, you get navigation anchors for free with no extra work. That means you can add
#your-id to the end of any URL and jump straight to that ID's location on page load. Incredibly useful!
That's how this post's table of content works, for example. Go on — go back to the table of contents and click on "IDs as an anchor for navigation". You'll come right back here 😊. I'll wait...
Finally, the good stuff!
This is where IDs shine (and why it's so important that they are unique)! Take this example from the Frontend Mentor 'Intro component with sign-up form' challenge:
Laying aside some of the accessibility issues like color contrast and the DOM order in this design (and laying aside the fact that this design would probably break EU law, which requires an explicit terms and conditions opt-in), I would write the mark up as follows:
<button type="button" aria-describedby="terms">
Claim your free trial
By clicking the button, you are agreeing to our <a href="/">Terms and Services</a>
✅ This is the perfect use case for an ID attribute!
Thanks to this little ID, aria-describedby can now programmatically link the terms to the form submit button. That means, on focus of the button, a screenreader will now announce
button, submit, by clicking the button you are agreeing...
Check out the HTML in this CodePen for more good use cases:
I hope this has helped you gain a deeper understanding of how powerful and important IDs can be in HTML.
Take this as both
- A challenge - to only use IDs for navigation and programmatically linking elements
- And an opportunity - to learn a little sprinkling of aria 😉
Just remember - no aria is often better than the wrong aria! So test, test, test! And ask for help and feedback from others while you practice.