CSS selectorSelectors

[attribute]

Selects elements by an HTML attribute and its value: exact, starting, ending, a fragment, or a word from a list.

On this page

Example

#
CSS
a[href^="https"]::after {
  content: " ↗";
}

a[href$=".pdf"]::before {
  content: "PDF";
  margin-right: 6px;
  padding: 1px 5px;
  border-radius: 4px;
  background: #f43f5e;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
}
Preview

Definition and usage

#

You write an attribute selector in square brackets. [title] alone selects every element that has a title attribute, regardless of its value, even an empty one. Once you add an operator and a value, you’re checking the attribute’s content: the exact value, its start, its end, any fragment, or a single word from a list.

It’s a convenient way to style elements without adding classes. You can tell form fields apart by their type (input[type="email"]), external links by the start of the address (a[href^="https"]), and files by their extension (a[href$=".pdf"]). It also works great with data-* and aria-* attributes, which describe a component’s state, for example [aria-expanded="true"].

A quoted value is always safe. You can only drop the quotes when the value is a simple word of letters, digits, hyphens, and underscores that doesn’t start with a digit. Case in the value usually matters, unless you add the i flag before the closing bracket.

An attribute selector’s specificity is (0, 1, 0), the same as a class. You’ll run into the |= operator less often: [lang|="en"] matches the value en as well as values that start with en-, such as en-US.

Syntax

#
Syntax
[attribute] | [attribute="v"] | [attribute^="v"] | [attribute$="v"] | [attribute*="v"] | [attribute~="v"] | [attribute|="v"] | [attribute="v" i]

Notation variants

#
  • [title]

    [attribute]

    Only the presence of the attribute counts, the value doesn’t matter. Only the link with a title attribute matches.
  • [data-tags="css-grid"]

    [attribute="v"]

    Exactly that value, character for character. The element with "css new" doesn’t match, even though it also contains the word css.
  • [href^="https"]

    [attribute^="v"]

    The value starts with the given text. This is the usual way to flag external links.
  • [href$=".pdf"]

    [attribute$="v"]

    The value ends with the given text. The file MAP.PDF doesn’t match, because case matters.
  • [href*="files"]

    [attribute*="v"]

    The given text appears anywhere in the value, even in the middle of the address. Both links to files match.
  • [data-tags~="css"]

    [attribute~="v"]

    The value is a list of space-separated words, and one of them is exactly "css". The word "css-grid" doesn’t count.
  • [href$=".pdf" i]

    flag i

    The i flag turns off case sensitivity, so both PDF files match: lowercase and uppercase.

Notation variants in practice

#

[title]

Only the presence of the attribute counts, the value doesn’t matter. Only the link with a title attribute matches.
[title] { background: #7c3aed; color: #fff; }

[data-tags="css-grid"]

Exactly that value, character for character. The element with "css new" doesn’t match, even though it also contains the word css.
[data-tags="css-grid"] { background: #7c3aed; color: #fff; }

[href^="https"]

The value starts with the given text. This is the usual way to flag external links.
[href^="https"] { background: #7c3aed; color: #fff; }

[href$=".pdf"]

The value ends with the given text. The file MAP.PDF doesn’t match, because case matters.
[href$=".pdf"] { background: #7c3aed; color: #fff; }

[href*="files"]

The given text appears anywhere in the value, even in the middle of the address. Both links to files match.
[href*="files"] { background: #7c3aed; color: #fff; }

[data-tags~="css"]

The value is a list of space-separated words, and one of them is exactly "css". The word "css-grid" doesn’t count.
[data-tags~="css"] { background: #7c3aed; color: #fff; }

[href$=".pdf" i]

The i flag turns off case sensitivity, so both PDF files match: lowercase and uppercase.
[href$=".pdf" i] { background: #7c3aed; color: #fff; }

More examples

#
A component’s state stored in an ARIA attribute
CSS
.toggle[aria-expanded="true"] {
  background: #7c3aed;
}

.toggle[aria-expanded="false"] + .details {
  display: none;
}
Preview

Click the button. The script only changes the aria-expanded value; the button’s color and the visibility of the details come entirely from CSS.

Browser support

#

Widely available

Works in all modern browsers, phones included. You can use it without worry.

  • Chrome
  • Edge
  • Firefox
  • Safari

Good practices

#
  • Keep a component’s state in attributes like aria-expanded or data-state, and style it with an attribute selector. The look will always match what screen reader users hear.
  • An attribute selector only sees attributes written in the HTML. input[value=""] won’t react to typing, and [checked] won’t react to clicking the field. Pseudo-classes like :checked and :placeholder-shown handle the live state.
  • Addresses and file extensions get written differently, so with ^=, $=, and *= it’s worth considering the i flag.

Related entries

#

Spotted a mistake or missing an example? Write to us.