Not every HTML element carries a convenient class or id to target. The attribute selector makes it possible to rely directly on attributes already present in the markup, without adding a single one.
It is a particularly useful tool on forms or on automatically generated content, where adding a class to every element would be tedious, or even impossible if the HTML comes from another system entirely.
Definition
The attribute selector targets an HTML element based on the presence or value of one of its attributes, written inside square brackets. The simplest form, [attribute], targets any element that has that attribute, no matter its value.
The matching variants
Beyond simple presence, CSS offers several operators to compare an attribute's value against a specific piece of text.
/* presence of the attribute, value ignored */
[disabled] {
opacity: 0.5;
}
/* value exactly equal */
input[type="email"] {
border-color: #999;
}
/* value STARTS WITH this text */
a[href^="https://"] {
color: green;
}
/* value ENDS WITH this text */
a[href$=".pdf"] {
padding-right: 20px;
}
/* value CONTAINS this text, anywhere */
a[href*="believemy"] {
font-weight: bold;
}The symbol placed before the equal sign changes the behavior: ^= for the start of a string, $= for the end of a string, *= for anywhere inside the value.
A typical use case
A common example is targeting form fields by their type, without adding a single class: input[type="email"] targets every email field in a form, even one generated by a third-party library that does not allow custom classes. It is also useful for styling external links, downloadable files, or elements carrying a data-* attribute added by JavaScript.
Case sensitivity
By default, attribute selector comparisons are case sensitive for most HTML attributes. A case insensitive comparison can be forced by adding the letter i right before the closing bracket, for example [lang="fr" i].
data-* attribute, it is worth relying on it directly.A complete example on a form
Picture a form generated by a third-party library, where every field follows an imposed structure with no way to add a custom class. The attribute-based CSS selector then becomes the only reliable option to visually tell apart required fields, fields in error, or fields already filled in.
/* required field */
input[required] {
border-left: 3px solid #e63946;
}
/* already filled and valid field */
input:not(:placeholder-shown):valid {
border-color: #2a9d8f;
}
/* checkbox already checked */
input[type="checkbox"][checked] {
accent-color: #2d6cdf;
}Paired with a CSS combinators, as in form input[required], the attribute selector makes it possible to scope the rule to a single form on the page, without ever depending on a class added by hand. This approach also pairs very well with the Class selector for cases where a class already exists, combining both inside a single compound selector.
Frequently asked questions
Yes, with no space between them, as in .field[required], which targets only elements carrying both the field class and the required attribute at once. This combination stays perfectly readable and removes the need to choose between the two approaches when they naturally complement each other on the same element.
Yes, it works on any attribute present in the HTML, including data-* attributes added by hand or generated dynamically by an application.
A selector that only checks for the attribute's presence, such as [disabled], still works even when the attribute carries no value at all, which is common for boolean attributes in HTML.