Skip to main content Skip to navigation
All Posts All Tags

What the ID attribute is REALLY for

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:

<h2 id="uniqueHeadingId">
This heading has an ID attribute.
</h2>

That uniqueHeadingId can be referenced and used in a variety of ways throughout Front End code. You'll see IDs in HTML, CSS and JavaScript, but that doesn't mean every code example is using them well!

Important points to note

A few quick caveats about this super-important little attribute...

  1. You don't need IDs on everything! Only add them when you need to (see uses below).

  2. IDs must not contain spaces or special characters. That's invalid HTML.

  3. 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'

What can IDs be used for?

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:

  1. As a CSS selector
  2. As a JS selector
  3. As an anchor for navigation
  4. 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.

ID as a CSS selector

Just because you can use ID attributes as style selectors, it doesn't mean you should. Example:

<!-- HTML -->
<p id="cool-id">...
/* CSS */
#cool-id {
...
}

⚠️ 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.

IDs as a JS selector

This isn't as bad and is certainly a more common practice you'll encounter. For example:

<!--HTML-->
<button id="super-cool-id">...
<button id="cool-id">...
/* 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!

It's sort of OK if your team has this as an established pattern because if IDs change, you and your team will know to go and check that any JavaScript functionality still works.

The problems come

  1. 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.
  2. When there is a lack of clarity (How would a dev looking at the HTML know that an ID is important for JS functionality?)
  3. 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.

IDs as navigation anchors

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...

IDs as element anchors

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:

Clipped portion of a design showing a button that says 'Claim your free trial' with writing underneath that says 'By clicking the button, you are agreeing to our Terms and Services' where terms and services is a link

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
</button>
<p id="terms">
By clicking the button, you are agreeing to our <a href="/">Terms and Services</a>
</p>

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:

Summing up

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.