Select elements by attribute in CSS
Asked Answered
T

7

571

Is it possible to select elements in CSS by their HTML5 data attributes (for example, data-role)?

Think answered 16/3, 2011 at 11:7 Comment(0)
B
894

If you mean using an attribute selector, sure, why not:

[data-role="page"] {
    /* Styles */
}

There are a variety of attribute selectors you can use for various scenarios which are all covered in the document I link to. Note that, despite custom data attributes being a "new HTML5 feature",

  • browsers typically don't have any problems supporting non-standard attributes, so you should be able to filter them with attribute selectors; and

  • you don't have to worry about CSS validation either, as CSS doesn't care about non-namespaced attribute names as long as they don't break the selector syntax.

Bestir answered 16/3, 2011 at 11:9 Comment(6)
Best list of selectors I've seen with capability and descriptions. code.tutsplus.com/tutorials/…Transfer
CSS doesn't seem to detect this if the data attribute is set, or changed via JS.Filippa
@Matthew T. Baker: Interesting, thanks. I can't claim to understand how datasets work under the hood, but it's likely modifying an element's dataset does not set or update its attribute list, which is what an attribute selector is really looking at. In other words, the transformation of data-attributes to a dataset only works one way - any changes to the latter are not reflected back.Bestir
After further investigation it would appear $("#element").data("field","value"); does not change the data attributes value it only modifies jQuery's cached version of the DOM. In order to change the actual DOM attribute one needs to use $("#element").attr("data-field","value");. Making my original comment invalid.Filippa
Yeah, looks like changing the dataset does work as well @Matthew - jsfiddle.net/BoltClock/k378xgj3 Thanks for nothing jQuery.Bestir
If you had <div data-role="page"><div class="foo">Content here</div></div> and wanted to change the style of the inner div, you could use [data-role="page"] .foo{background-color:red;} Omasum
C
139

It's also possible to select attributes regardless of their content, in modern browsers

with:

[data-my-attribute] {
   /* Styles */
}

[anything] {
   /* Styles */
}

For example: http://codepen.io/jasonm23/pen/fADnu

Works on a very significant percentage of browsers.

Note this can also be used in a JQuery selector, or using document.querySelector

Cauline answered 12/9, 2013 at 2:1 Comment(6)
Wow, I never saw it could be used like that!! +1! And FWIW, now that the browsershots is expired, I believe it works in IE7+ so its support is pretty much omnipresent. It's funny that not even Chris Coyier mentioned it hereBiddable
Thanks @CamiloMartin I've removed the browsershots link to avoid confusion / annoyance.Cauline
Added a link to Chris Coyier's thread css-tricks.com/attribute-selectors/#comment-965838 @CamiloMartinCauline
Great, the more who know the better :) and yep, confirmed to work on IE7+.Biddable
None of this syntax is new anyway - more people were surprised that IE6 did not support it than IE7+ does. You can pretty much assume all CSS2.1 selectors are supported in IE8 and later - IE7 does most, albeit with a few obscure bugs. All modern browsers have supported level 3 selectors for a while, with Chrome being the buggy one instead.Bestir
Since we're on the topic of attribute selectors though, it's interesting to note that the substring attribute selectors that were introduced in level 3 (^=, *= and $=) are also supported by IE7 and IE8. Maybe they were introduced in IE before being standardized.Bestir
C
69

It's worth noting CSS3 substring attribute selectors

[attribute^=value] { /* starts with selector */
/* Styles */
}

[attribute$=value] { /* ends with selector */
/* Styles */
}

[attribute*=value] { /* contains selector */
/* Styles */
}
Cottier answered 18/5, 2015 at 15:50 Comment(0)
M
25
    [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 */
}
Mars answered 3/1, 2020 at 10:18 Comment(0)
R
20

You can combine multiple selectors and this is so cool knowing that you can select every attribute and attribute based on their value like href based on their values with CSS only..

Attributes selectors allows you play around some extra with id and class attributes

Here is an awesome read on Attribute Selectors

Fiddle

a[href="http://aamirshahzad.net"][title="Aamir"] {
  color: green;
  text-decoration: none;
}

a[id*="google"] {
  color: red;
}

a[class*="stack"] {
  color: yellow;
}
<a href="http://aamirshahzad.net" title="Aamir">Aamir</a>
<br>
<a href="http://google.com" id="google-link" title="Google">Google</a>
<br>
<a href="http://stackoverflow.com" class="stack-link" title="stack">stack</a>

Browser support:
IE6+, Chrome, Firefox & Safari

You can check detail here.

Rockingham answered 30/3, 2016 at 4:1 Comment(1)
Is it not possible to combine several together in some kind of 'or' logic (if you want the same rules applied)? The only think I could get to work is a[id="google"], a[id="bing"], a[id="baidu"],... { color: pink; } which is fine and dandy with 'a', but if the element is long it is quite 'wordy'. I'd like a[id="google"|"bing"|"baidu"] or something like that.Wheaton
O
3

Is it possible to select elements in CSS by their HTML5 data attributes? This can easily be answered just by trying it, and the answer is, of course, yes. But this invariably leads us to the next question, 'Should we select elements in CSS by their HTML5 data attributes?' There are conflicting opinions on this.

In the 'no' camp is (or at least was, back in 2014) CSS legend Harry Roberts. In the article, Naming UI components in OOCSS, he wrote:

It’s important to note that although we can style HTML via its data-* attributes, we probably shouldn’t. data-* attributes are meant for holding data in markup, not for selecting on. This, from the HTML Living Standard (emphasis mine):

"Custom data attributes are intended to store custom data private to the page or application, for which there are no more appropriate attributes or elements."

The W3C spec was frustratingly vague on this point, but based purely on what it did and didn't say, I think Harry's conclusion was perfectly reasonable.

Since then, plenty of articles have suggested that it's perfectly appropriate to use custom data attributes as styling hooks, including MDN's guide, Using data attributes. There's even a CSS methodology called CUBE CSS which has adopted the data attribute hook as the preferred way of adding styles to component 'exceptions' (known as modifiers in BEM).

Thankfully, the WHATWG HTML Living Standard has since added a few more words and even some examples (emphasis mine):

Custom data attributes are intended to store custom data, state, annotations, and similar, private to the page or application, for which there are no more appropriate attributes or elements.

In this example, custom data attributes are used to store the result of a feature detection for PaymentRequest, which could be used in CSS to style a checkout page differently.

Authors should carefully design such extensions so that when the attributes are ignored and any associated CSS dropped, the page is still usable.


TL;DR: Yes, it's okay to use data-* attributes in CSS selectors, provided the page is still usable without them.

Olivas answered 2/2, 2021 at 7:30 Comment(5)
The person who downvoted this answer (within hours of me writing it) didn't explain why, so I can only guess they considered it off-topic. The questions of whether we can do something and whether we should are inextricably linked when it comes to writing code. Any developer who strives to write good code (that is, code that not only gets the job done, but also adheres to best practice) will ask this question, so the answer was shared to fill that gap.Olivas
I have not voted yet one way or the other but I would venture a guess that the person who did downvote did so because this answer spends one sentence repeating the answer to the question, and then the rest of the time is spent answering a completely different question. I'm not convinced it's even "new information" since it's inherent in the fact that it's a feature that it "should be done". If it shouldn't, it probably wouldn't be a feature in the spec.Reneta
Thanks @TylerH. When you say, 'it probably wouldn't be a feature in the spec' if it shouldn't be done, that's actually my point. Web browsers are very forgiving by design—the web wouldn't be such a fun place if they just spat out an error every time they encountered some invalid HTML. So as developers, the questions of 'can we' and 'should we' are not divorced from each other. We can answer the former by testing, but we can answer both by referring to the spec. That's what was lacking from all the previous answers and why I provided mine.Olivas
@Reneta It's worth distinguishing here between the statements "you generally shouldn't do this/you generally shouldn't need to do this", and "under no circumstances should you ever do this". If it's in the spec, it does seem reasonable to assume there are some scenarios in which you might need to do it. But that doesn't mean it it's a good idea to be doing it often. This is the case for most patterns that are considered best practice. The existence of exceptional cases doesn't stop rules of thumb from being useful.Audsley
Loved this answer. Thanks!Mongrelize
B
1

The Seven Different Types

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

[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 */
}

attribute value strings can be changed to case-insensitive by adding i just before the closing bracket:

[attribute="value" i] {
  /* Styles here will apply to elements with:
    attribute="value"
    attribute="VaLuE"
    attribute="VALUE"
    ...etc
  */
}

for more information visit this link

Buckeye answered 3/12, 2023 at 11:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.