Match presence.div[lang] selects divs that declare lang.
Invert with :not().div:not([lang]) selects the rest.
Apply different styles. Bold vs italic shows both groups.
Reuse the idea. Same pattern works for required, disabled, and more.
Edge Cases & Pitfalls
Presence is simple—most mistakes come from expecting a value check.
value
[attr] does not read the value
href="" still matches [href]. Empty is still present. Use equals or other operators to filter values.
boolean
Boolean attributes count as present
<input disabled> matches [disabled] even with no value written.
case
Value case depends on the attribute
HTML attribute names are case-insensitive. Values like class / id / data-* are case-sensitive unless you add i.
quotes
Quote values with spaces
For value operators, quote strings that contain spaces or special characters: [title="Hello world"].
vs class
Prefer .class for class names
[class] only checks that class exists. To target a class name, use .name or [class~="name"].
Compatibility
Browser Support
Attribute selectors are browser CSS selectors. Node.js, Deno, and Bun do not evaluate them.
✓ Baseline · Widely available
[attr] presence
Core attribute selectors are Baseline Widely available. The case-sensitive s flag has more limited support than the base syntax.
99%All modern browsers
Google ChromeAll
Full
Mozilla FirefoxAll
Full
Apple SafariAll
Full
Microsoft EdgeAll
Full
OperaAll
Full
Samsung InternetAll
Full
Internet Explorer7+
Full
[attr]Universally supported
Bottom line: Production-ready for [attr] and common value operators. Prefer i for case-insensitive value matches when needed; treat s as optional.
Remember
Key Takeaways
Role: match elements that have a named attribute, any value.
Form:[attr] or element[attr].
Family: use =, *=, ^=, $=, ~=, |= when the value matters.
Tip: invert with :not([attr]) to style missing attributes.
One line:[attr] means “this attribute exists”—not “it equals this value.”
Frequently Asked Questions
It matches any element that has the named attribute set in the HTML, no matter what the attribute’s value is.
[href] only checks that the attribute exists. [href="https://example.org"] requires an exact value match.
Yes. input[placeholder] matches only input elements that have a placeholder attribute.
Use :not([attr]), for example div:not([lang]) for divs that have no lang attribute.
In HTML, attribute names are case-insensitive. Value matching depends on the attribute: class, id, and data-* are case-sensitive unless you add the i flag.
No. It is a browser CSS selector, not a Node.js feature.