11

Is there a way to select all custom elements with CSS? I want to make all custom elements block elements by default (most browsers make them inline by default), and then override this as necessary.

My rule may look something like this:

*::custom {
    display: block;
}

All custom elements have dashes in the standard, so I could create a rule taking advantage of that, but it would be slower on many/most current browsers, as it would need to use regular expressions. If there were a built-in selector, this would probably be faster.

Hashem Qolami
  • 97,268
  • 26
  • 150
  • 164
trysis
  • 8,086
  • 17
  • 51
  • 80
  • 1
    So how many custom elements do you have in your project? 5, 10, 20? It's simpler just write rules manually and forget about it: `x-one, x-two, ..., x-xxx {display: block;}`. – dfsq Jul 17 '15 at 17:00
  • 1
    AFAIK, there is no such pseudoselector, nor does CSS support partially wildcarded names in the selectors (though it is an obvious enhancement). – RBarryYoung Jul 17 '15 at 17:02
  • 1
    "Most browsers make them inline by default": that's because the initial value of `display` is `inline`. – Oriol Jul 17 '15 at 17:05
  • Can you not add `class` or `data-` attributes? – Jacob Jul 17 '15 at 17:06
  • @divinecomedian, As the Angular documentation says (this relates to directives, but can also apply to elements/attributes, as that is what directives are): "Use an element when you are creating a component that is in control of the template. The common case for this is when you are creating a Domain-Specific Language for parts of your template. Use an attribute when you are decorating an existing element with new functionality." – trysis Jul 17 '15 at 18:04
  • @divinecomedian, Elsewhere, it says (again for directives but can be applied elsewhere): "Prefer using directives via tag name and attributes over comment and class names. Doing so generally makes it easier to determine what directives a given element matches." – trysis Jul 17 '15 at 18:05
  • So "yes" or "no"? lol Sorry I've never used Angular. – Jacob Jul 17 '15 at 18:40
  • I could, but I don't really want `
    ` everywhere, I want `` or ``. As I said, this isn't an Angular-specific behavior, Angular just abstracts some of the common difficulties away.
    – trysis Jul 17 '15 at 19:44
  • possible duplicate of [Using custom HTML Tags](http://stackoverflow.com/questions/5970093/using-custom-html-tags) – sergdenisov Jul 17 '15 at 20:17
  • @SergeyDenisov, this is not a duplicate of that question, and not really that related, though I can see why you would think that. That question asks whether it is OK to use HTML tags (it is, much more so than when the question was asked), while this question asks about a CSS selector for all custom elements. – trysis Jul 17 '15 at 21:11
  • Such a selector would have to be a pseudo-class rather than a pseudo-element, since you're targeting elements. In any case, I don't think such a selector exists - and it would be difficult to spec one because what exactly constitutes a custom element? An element whose tagname matches a user- or impl-defined prefix? Any non-standard element (what is considered "standard"?)? In the case of XML, an element in an XML namespace other than the default? – BoltClock Jul 18 '15 at 07:32
  • As I said, all non-standard elements have dashes in them, according to the standard. Of course not everyone will follow that, but I'm assuming (hoping) the major ones will and I would if using a selector like this. – trysis Jul 18 '15 at 13:55
  • @BoltClock, So for everyone following that standard, there should be a way to specify *all* custom elements. I'm asking whether or not there is a built-in selector for this yet. – trysis Jul 20 '15 at 13:50

7 Answers7

5

No, there isn't a pseudo selector to do that.

One certainly not optimal solution, however, would be to use this type of CSS:

:not(html, head, body, h1, h2, h3, h4, h5, h6, div, ...) {
  /* Code here */
}

It would work! On the down side if ever new elements are added you need to add that element into your not-selector. Yay.

^.^

Nebula
  • 6,614
  • 4
  • 20
  • 40
4

Add an inert custom attribute to your custom elements:

<some-element cutom-elem /> <other-element custom-elem />
<script> 
  var customs = document.querySelectorAll( "*[custom-elem]" )
</script>
<style>
    *[custom-elem] { display: block ; }
</style>
Supersharp
  • 29,002
  • 9
  • 92
  • 134
  • This could work (though I would put `data-` at the beginning of the custom attribute), and is similar to what I was doing. Now I removed many custom elements because I realized some built-in elements are OK. I would just rather not add more attributes than I have to. – trysis Aug 10 '15 at 15:23
3

Here's a workaround based on Florrie's answer: :not(html):not(head):not(title):not(base):not(link):not(meta):not(style):not(body):not(article):not(section):not(nav):not(aside):not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(hgroup):not(header):not(footer):not(address):not(p):not(hr):not(pre):not(blockquote):not(ol):not(ul):not(li):not(dl):not(dt):not(dd):not(figure):not(figcaption):not(div):not(main):not(a):not(em):not(strong):not(small):not(s):not(cite):not(q):not(dfn):not(abbr):not(data):not(time):not(code):not(var):not(samp):not(kbd):not(sub):not(sup):not(i):not(b):not(u):not(mark):not(ruby):not(rb):not(rt):not(rtc):not(rp):not(bdi):not(bdo):not(span):not(br):not(wbr):not(ins):not(del):not(picture):not(img):not(iframe):not(embed):not(object):not(param):not(video):not(audio):not(source):not(track):not(map):not(area):not(math):not(svg):not(table):not(caption):not(colgroup):not(col):not(tbody):not(thead):not(tfoot):not(tr):not(td):not(th):not(form):not(label):not(input):not(button):not(select):not(datalist):not(optgroup):not(option):not(textarea):not(keygen):not(output):not(progress):not(meter):not(fieldset):not(legend):not(script):not(noscript):not(template):not(canvas)

Additionally, you will have to account for SVG and MathML namespaces.

  • One way would be to just add their tags in a similar manner.
  • In some cases (ad-blocking), it might be sufficient to prepend that selector with a few possible parents to avoid <svg> and <math> children. Something like :-webkit-any(body, div) > :not(.... See :is(), :matches(), :any().
  • Once implemented, Selectors Level 4 should allow something like :not(math *, svg *).
  • @namespace can be used, something like @namespace xhtml "http://www.w3.org/1999/xhtml"; xhtml|*:not(....
Abradoks
  • 39
  • 1
  • The specificity on this selector.....Each :not() is another 10 specificity points. The only way to beat that selector is with an ID. – augurone Sep 21 '21 at 17:26
1

You could do this using slightly modified code from this answer to get all registered custom tag names:

function getCustomElements() {
    const allElems = document.getElementsByTagName("*");
    let elementNames = [].map.call(allElems, el => el.nodeName.toLowerCase())
    elementNames = [...new Set(elementNames)];
    return elementNames.filter(name => customElements.get(name));
}

Which you can then use to style all custom elements:

const customElementSelector = getCustomElements().join();
document.querySelectorAll(customElementSelector).forEach(el => {
    el.style.border = "solid";
});
Tentacola
  • 11
  • 1
  • Where does `customElements` get defined? Is that a built-in property on `window`? I didn't see it in the answer you linked to, either. – trysis Apr 22 '20 at 11:11
  • Yes it is, I slightly modified the code of the other answer but the logic behind it is the same https://developer.mozilla.org/en-US/docs/Web/API/Window/customElements – Tentacola Apr 24 '20 at 08:32
1

If you just want to use custom tags instead of div:

:where(:not(:defined)) { 
    display: block; 
}

:not(:defined) selects the elements that are neither built in nor defined by you with customElements.define().

:where gives this rule low specificity, to avoid breaking grid, flow and display:inline.

This does not change the default inline display of actual custom elements that you pass to customElements.define(). I don't think it's a burden, as we already write specific code for such elements anyway.

really
  • 93
  • 7
  • 1
    The problem with this is that your custom elements ought to defined by your code if you're intending on using them and when they're defined this selector of course won't work for you. – robstarbuck Oct 03 '22 at 17:24
  • Of course. As I stated from the start, it's not for actual custom elements, it's just for replacing div with custom tags. – really Oct 12 '22 at 06:33
1

Using javascript, this will return an array of custom elements

Array.from(document.querySelectorAll('*')).filter(el => el.tagName.includes('-'))
Zuhair Taha
  • 2,808
  • 2
  • 35
  • 33
-3

You can simply use css like below:

custom-element{
    color: white;
    min-height: 20px;
}

I have tested this in Firefox and Chrome. Not sure about actual compatibility though. Please test on your environments.