Published at
Updated at
Reading time
2min
This post is part of my Today I learned series in which I share all my web development learnings.

Here's a trick question: how would you select the following HTML element in JavaScript?

<div id="#">Select me!</div>

Oddly, this element's id is a #. But as far as I can tell, even though it's uncommon it's still a perfectly valid HTML attribute. So, how would you query this element?

You surely could use the good old document.getElementById()...

console.log(document.getElementById('#')); // <div id="#">...

This works, but I rarely use getElementById because it limits me to select elements via an id. Duh! ๐Ÿ˜…

document.querySelector, on the other hand, is more flexible and allows any DOM element to be queried with a CSS selector.

But can you select this "hash id element" with a CSS selector using querySelector? Turns out you can't.

console.log(document.querySelector('##'));
// SyntaxError: Document.querySelector: '##' is not a valid selector

Unfortunately, ## isn't a valid CSS selector, and I hear you say, "Come on Stefan, espace the second # and you're good to go!" and that's right, escaping the # character works.

console.log(document.querySelector('#\\#')); // <div id="#">...

But do you know all the characters that need to be escaped when you want to query a DOM element? Plenty of valid HTML attribute strings will throw an exception when used to query a DOM element.

document.querySelector('.a:b');     // throws because of the `:`
document.querySelector('[href=@]'); // throws because of the `@`
document.querySelector('.[jooo]');  // throws because of the `[]`

Manually escaping characters isn't a bulletproof solution, but today I learned there's a handy static method in the CSS JavaScript namespace to help with this exact problem โ€” CSS.escape().

escape() allows you to safely use whatever attribute values your HTML includes.

console.log(`.${CSS.escape('a:b')}`);      // ".a\:b"
console.log(`[href=${CSS.escape('@')}]`); // "[href=\@]"
console.log(`.${CSS.escape('[jooo]')}`);  // ".\[jooo\]"

Good to know!

You might wonder how often you have to deal with these unusual attribute values. For example, the useId React hook returns ids that are invalid as CSS selectors. That's one case already, and I bet there are plenty more!

If you enjoyed this article...

Join 5.5k readers and learn something new every week with Web Weekly.

Web Weekly โ€” Your friendly Web Dev newsletter
Reply to this post and share your thoughts via good old email.
Stefan standing in the park in front of a green background

About Stefan Judis

Frontend nerd with over ten years of experience, freelance dev, "Today I Learned" blogger, conference speaker, and Open Source maintainer.

Related Topics

Related Articles