Select elements by declared attributes
Attribute selectors match an attribute's presence or value. They are useful for form input types, data attributes and link patterns. They inspect attributes, not every changing JavaScript property, so choose state pseudo-classes when you need live control state.
input[required] { border-left: 3px solid #2563eb; }
input[type="email"] { max-width: 28rem; }
[data-state="error"] { color: #991b1b; }
a[href^="https://"] { text-underline-offset: 0.2em; }
a[href$=".pdf" i] { font-weight: 600; }Square brackets with no comparison test presence. ^= tests a prefix, $= a suffix and *= a substring. The i flag requests ASCII case-insensitive matching for that comparison. A PDF link containing a query string after .pdf will not match the simple suffix rule; select a meaningful class or data attribute if that distinction matters.
Token matching
[class~="featured"] matches a whitespace-separated token, similarly to .featured. [lang|="en"] matches en or a value beginning en- and is useful for language subtags. Substring matching is broader and can accidentally match unrelated values.
State is not always an attribute
For a checkbox, use :checked to style its current checked state. The checked attribute describes the initial/default state and need not track every user toggle. Likewise, attributes do not replace the semantic required, disabled or type behavior supplied by HTML.
Security and accessibility
A link whose text or URL resembles a trusted domain is not automatically safe. Styling a link with an attribute selector performs no security validation. A disabled-looking element also remains interactive unless the underlying control's behavior is actually changed.
Practice
- Create email, password and text inputs, then style only email inputs.
- Add data-state="error" to a status paragraph and provide an actual explanatory message.
- Compare [class*="card"] with .card using classes card and postcard. The substring selector matches both; the class selector matches only the card token.