There are lots of ways you can select elements in CSS. The most basic selection is by tag name, like p { }. Almost anything more specific than a tag selector uses attributes — class and ID both select on those attributes on HTML elements. But class and ID aren't the only attributes developers can select. We can use any of an element's attributes as selectors.

Attribute selection has a special syntax. Here's an example:

a[href="https://css-tricks.com"] {
  color: #E18728;

That's an exact match selector that will only select links with the exact href attribute value of "https://css-tricks.com".

The Seven Different Types

Attribute selectors are case-sensitive, and are written inside brackets [].

There are seven different types of matches you can find with an attribute selector, and the syntax is different for each. Each of the more complex attribute selectors build on the syntax of the exact match selector — they all start with the attribute name and end with an equals sign followed by the attribute value(s), usually in quotes. What goes between the attribute name and equals sign is what makes the difference among the selectors.

[data-value] {
  /* Attribute exists */

[data-value="foo"] {
  /* Attribute has this exact value */

[data-value*="foo"] {
  /* Attribute value contains this value somewhere in it */

[data-value~="foo"] {
  /* Attribute has this value in a space-separated list somewhere */

[data-value^="foo"] {
  /* Attribute value starts with this */

[data-value|="foo"] {
  /* Attribute value starts with this in a dash-separated list */

[data-value$="foo"] {
  /* Attribute value ends with this */

Value contains: attribute value contains a term as the only value, a value in a list of values, or as part of another value. To use this selector, add an asterisk (*) before the equals sign. For example, img[alt*="art"] will select images with the alt text "abstract art" and "athlete starting a new sport", because the value "art" is in the word "starting".

Value is in a space-separated list: value is either the only attribute value, or is a whole value in a space-separated set of values. Unlike the "contains" selector, this selector will not look for the value as a word fragment. To use this selector, add a tilde (~) before the equals sign. For example, img[alt~="art"] will select images with the alt text "abstract art" and "art show", but not "athlete starting a new sport" (which the "contains" selector would select).

Value starts with: attribute value starts with the selected term. To use this selector, add a caret (^) before the equals sign. Don't forget, case-sensitivity matters. For example, img[alt^="art"] will select images with the alt text "art show" and "artistic pattern", but not an image with the alt text "Arthur Miller" because "Arthur" begins with a capital letter.

Value is first in a dash-separated list: This selector is very similar to the "starts with" selector. Here, the selector matches a value that is either the only value or is the first in a dash-separated list of values. To use this selector, add a pipe character (|) before the equals sign. For example, li[data-years|="1900"] will select list items with a data-years value of "1900-2000", but not the list item with a data-years value of "1800-1900".

Value ends with: attribute value ends with the selected term. To use this selector, add a dollar sign ($) before the equals sign. For example, a[href$="pdf"] selects every link that ends with .pdf.

A note about quotes: You can go without quotes around the value in some circumstances, but the rules for selecting without quotes are inconsistent cross-browser. Quotes always work, so if you stick to using them you can be sure your selector will work.

See the Pen Attribute Selectors by CSS-Tricks (@css-tricks) on CodePen.

Fun fact: the values are treated as strings, so you don't have to do any fancy escaping of characters to make them match, as you would if you used unusual characters in a class or ID selector.

[class="(╯°□°)╯︵ ┻━┻"]{
  color: red;
  font-weight: bold;

Combining them

You can combine an attribute selector with other selectors, like tag, class, or ID.

div[attribute="value"] {
  /* style rules here */

.module[attribute="value"] {
  /* style rules here */

#header[attribute="value"] {
  /* style rules here */

Or even combine multiple attribute selectors. This example selects images with alt text that includes the word "person" as the only value or a value in a space separated list, and a src value that includes the value "lorem":

img[alt~="person"][src*="lorem"] {
  /* style rules here */

See the Pen Combined Attributes and Attribute-Only Selection by CSS-Tricks (@css-tricks) on CodePen.

Attribute Selectors in JavaScript and jQuery

Attribute selectors can be used in jQuery just like any other CSS selector. In JavaScript, you can use attribute selectors with document.querySelector() and document.querySelectorAll().

See the Pen Attribute Selectors in JS and jQuery by CSS-Tricks (@css-tricks) on CodePen.


More Information

Browser Support

Chrome Safari Firefox Opera IE Android iOS
Any Any Any Any 7+ Any Any


  1. User Avatar
    Druid of Lûhn
    Permalink to comment#

    About using [rel$=external], you could use it with an :after selector on links ending in “.pdf” to have an icon at the end.

  2. User Avatar
    Permalink to comment#

    Do Multiple attribute work in all browser?

  3. User Avatar
    Permalink to comment#

    While I like the power of these, I’m regularly frustrated that they don’t seem to be dynamic:

    input[checked]:after {
      content: attr(name);
      background-color: green;
      position: absolute;
        <li><input type=checkbox name='unchkd'>unchecked</input>
        <li><input type=checkbox name='chkd' checked>checked</input>

    which I keep hoping would update the CSS based on the “checked” property toggling on/off. Alas, not.

    • User Avatar

      you mean like this…

    • User Avatar

      Sorry, “checked” may have been a poor choice of example since the :checked would suffice. A better example might be the .value of a select-list

       .optional {
        display: hidden;
       select[value="other"] ~ .optional {
        display: block;
      Please let us know why you rated us "Excellent"
        <option value="service">Great service</option>
        <option value="price">Great price</option>
        <option value="adorable">Adorable puppies!</option>
        <option value="other">Other</option>
      <label class=optional>Please let us know what other reason
      <input type="text">

      AFAIK, there’s no way in pure CSS to change layout based on the value of a select drop-down or the text-value of an input box. So if I wanted to make my other text-input only show when “Other” is selected, it currently requires JS.

    • User Avatar
      Permalink to comment#

      Input and Select

      I handle this by having my startup JS give input and select elements having attribute data-value an “onchange” handler (or “change” event listener) that does this.dataset.value=this.value (remember to use .bind(elm) or a factory function). Although this solution is not pure CSS, it’s a mere whiff of boilerplate JS code to let CSS handle dependent display elements like magic in most any project (adapt to use your framework’s selector function and iterator):

      $$('input[data-value], select[data-value]').forEach(elm => {

      Then the CSS for @Gumnos’ post would need only a minor change, to prefix “data-” in the attribute selector:

       .optional {
        display: hidden;
       select[data-value="other"] ~ .optional {
        display: block;

      On a related topic…

      For a checkbox (and radiobutton) solution, I set specific classes on the controlling and target elements, and craft CSS to handle an element hierarchy of both child and following-sibling. The CSS selectors for the controlling classes are combined with :checked or :not(:checked) as needed.

      This solution is pure CSS, plus the relationship between elements is explicitly stated in the markup, so it’s easy for the designer to understand and manage.

      Depending on your project you can limit yourself to a couple of simple selectors like .controlFollowing:checked and .targetFollowing (provided you put each set in a wrapper element), or you can have incredibly detailed multi-step control by using selectors such as .controlFollowing1:checked .targetFollowing1 and .controlFollowing1:not(:checked) .targetFollowing1 and extend the numbers as needed. I’ve built up a library file I link when I need this feature, but I caution you not to extend the idea more than a project warrants.

      In live code, most of the time, a small simple style set suffices:

      .controlFollowing ~ .targetFollowing
      ,.controlChild > .targetChild
      {display: none; }
      .controlFollowing:checked ~ .targetFollowing
      , .controlChild:checked > .targetChild
      {display: initial; }
               Yes, Virginia...
           Toggle, too? 
                  Far out! 
    • User Avatar
      Permalink to comment#

      This would work

        --optional: hidden;
        display: var(--optional);
      select[value="other"] ~ .optional {
         --optional: block;
  4. User Avatar
    Permalink to comment#

    Thanks @Chris you are ‘Superman’

  5. User Avatar
    Permalink to comment#

    How would I write the css for this?

    <option data-hidden="true" value="">[Fornecedor]</option>

    I’ve tried

    option[data-hidden="true"]{color: green;}
    option[data-hidden]{color: green;}
    option[dataHidden] {color: green;}

    all to no avail.

    Thanks in advance

    • User Avatar
      Permalink to comment#

      I have a similar problem. It seems not to work on element selectors (I’ve tried it on ).
      You could add a class to your element and use the attribute selector on the class. That works for me.

    • User Avatar
      Permalink to comment#

      I meant so say I’ve tried it on <button> ;)

  6. User Avatar
    Permalink to comment#

    how to select a list in css .main please tell about code is it like or li should be used in place of a

    .nav a{
  7. User Avatar
    Permalink to comment#

    What if I wanted to change the value of a data attribute with CSS. For instance:

    @media screen and (max-width: 639px) {
        img[align="right"] {
          border: 4px solid pink;
          /* change "right" to "middle" */

    I know this can easily be down with JS, but what about pure CSS?

  8. User Avatar
    Permalink to comment#

    Do browsers distinguish between standard HTML attributes (like href or class) and custom ones?
    I see you used “data-value” a lot on your examples, but can I use custom attributes without the data-* in the end and select it usng CSS (for instance, [tricks=’attr’]{})?

    Thanks for your help.

  9. User Avatar
    Permalink to comment#

    Anyone have trouble with iPhone5 ignoring/not seeing something like this?


    iPhone6 seems to have no problem, but iPhone5 ignores all related styling.

  10. User Avatar
    Permalink to comment#

    Which software should I use to learn CSS plz reply as fast as you can

  11. User Avatar
    Permalink to comment#

    Wow! Thanks for this explanation, after carefully reading over and over I was able to apply it to a complex challenge and it work.

    Thanks once again

  12. User Avatar
    Gustavo Costa
    Permalink to comment#

    If I want to select many icons for img[icone], adding class, would it be img[icone][class^=”icosv-“]:before?

  13. User Avatar

    Whow! Why didn’t I think of this before, just fabulously powerful and convenient!

  14. User Avatar
    Permalink to comment#

    Is it possible somehow to extract meta tag content ?

Leave a Comment

Posting Code!

You may write comments in Markdown. This makes code easy to post, as you can write inline code like `<div>this</div>` or multiline blocks of code in triple backtick fences (```) with double new lines before and after.

Code of Conduct

Absolutely anyone is welcome to submit a comment here. But not all comments will be posted. Think of it like writing a letter to the editor. All submitted comments will be read, but not all published. Published comments will be on-topic, helpful, and further the discussion or debate.

Want to tell us something privately?

Feel free to use our contact form. That's a great place to let us know about typos or anything off-topic.