Skip to content

:predefined pseudo-class for built-ins (i.e. not custom elements) #11001

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
LeaVerou opened this issue Oct 4, 2024 · 9 comments
Open

:predefined pseudo-class for built-ins (i.e. not custom elements) #11001

LeaVerou opened this issue Oct 4, 2024 · 9 comments
Labels
HTML Requires coordination with HTML people

Comments

@LeaVerou
Copy link
Member

LeaVerou commented Oct 4, 2024

It is currently impossible to match custom elements generically. :not(:defined) matches custom elements that have not yet been defined, but since :defined also matches built-ins, there is no way to target all custom elements.

Admittedly the use cases for this are niche (it came up in a Twitter discussion with a framework author who said they use a different code path when the template contains custom elements), but also it’s a pretty simple addition, so why not.

We could introduce a :predefined pseudo-class to match native elements, authors can simply use :not(:predefined) to match custom elements. Or we could introduce a pseudo-class to directly match custom elements, though I have no idea what to call it 🙃

(Ideally we should eventually introduce more granular selectors to target element by tag prefix and/or suffix but this is a nice quick fix that can be implemented pretty easily, and is useful in its own right.)

@LeaVerou LeaVerou added the HTML Requires coordination with HTML people label Oct 4, 2024
@sorvell
Copy link

sorvell commented Oct 7, 2024

Then to match defined custom elements, you'd need :defined:not(:predefined)? Verbose but explicit and likely uncommon, seems fine.

@sorvell
Copy link

sorvell commented Oct 7, 2024

Unfortunately, customized built-ins still exist despite Webkit not supporting them, so they probably need to be accounted for here:

  1. <input> matches :defined
  2. <input is="x-foo"> does not match :defined

Presumably then via this proposal:

  1. <input> matches :predefined
  2. <input is="x-foo"> does not match :predefined

@Westbrook
Copy link

Westbrook commented Nov 1, 2024

Expanding the use case (from #11140) by @KonnorRogers...

Proposal

Add a selector to only target built in elements.

Why?

with custom elements being more and more prevalent, it's sometimes important to separate custom elements from built in elements, especially with things like CSS resets.

common scenario in a CSS reset such as Tailwind:

* {
  border: 0;
}

but this can mess up custom elements that use a :host { border: 1px solid black; } css rule.

with a pseudo selector like :builtin CSS resets could target only built in elements.

:builtin {
  border: 0;
}

other scenarios:

  • Form Controls. with the advent of Form Associated Custom Elements, :invalid, :valid, et al may have unintended consequences if used on custom elements. With :builtin:disabled for example you can guarantee you're only targeting native elements.
:builtin:invalid {
  outline: 2px solid red;
}
  • setting display: contents; on all custom elements regardless of if they're defined or not.
:not(:builtin) {
  display: contents;
}

issues with :defined

:defined is too broad since it will count both defined custom elements and built in elements and there's no way to distinguish.

:not(:defined) misses cases where you define a custom element but it only is defined for attaching JS and has no presentational aspect.

@Westbrook
Copy link

Something in this area would be a nice win. Whether el.match(:not(:predefined)) were able to be faster than !customElements.getName(el) would be an interesting bake-off.

Small bit of bikeshedding: :predefined feels "time relative" to :defined. It also sounds like it leans closer to the needs outlined in whatwg/html#6231 when you say it to many times.

@KonnorRogers
Copy link

KonnorRogers commented Nov 1, 2024

Something in this area would be a nice win. Whether el.match(:not(:predefined)) were able to be faster than !customElements.getName(el) would be an interesting bake-off.

Small bit of bikeshedding: :predefined feels "time relative" to :defined. It also sounds like it leans closer to the needs outlined in whatwg/html#6231 when you say it to many times.

FWIW, !customElements.getName(ctor) and :not(:predefined) aren't equivalent.

:not(:predefined) is more like :not(textarea, input, h1, h2, h3) {} whereas customElements.getName(ctor) checks for the element in the custom registry which may return false if the custom element is presentational only and never defines itself in the registry.

So for example, if I had <my-custom-element>, but never register it, then the !customElements.getName(ctor) will erroneously return true.

The "easy" way to check custom elements from JS is to do: el.localName.includes("-") but CSS doesn't have a tag selector that would match that.

/* pseudo code for tag selecting */
*-* {
}

@Westbrook
Copy link

FWIW, !customElements.getName(ctor) and :not(:predefined) aren't equivalent

Really great point and definitely belies an assumption on my past as to why “a framework author who said they use a different code path when the template contains custom elements” might want this feature. Hopefully we can get people representing this need involved in the conversation!

@titoBouzout
Copy link

titoBouzout commented Nov 4, 2024

Thanks for liking me the issue. What we want is node.isWebElement to be true when it's a web-element. This is differently than having - in the tagName. Is not the same to have a - than to be a web-element.

The CSS selector, would be nice I guess, but when you are in a hot path, you do not want to query-selector/match anything at all, you just want to know if a given element is a web-element or not.

@KonnorRogers
Copy link

Thanks for liking me the issue. What we want is node.isWebElement to be true when it's a web-element. This is differently than having - in the tagName. Is not the same to have a - than to be a web-element.

The CSS selector, would be nice I guess, but when you are in a hot path, you do not want to query-selector/match anything at all, you just want to know if a given element is a web-element or not.

Correct. Nothing is stopping someone from doing:

<myspecialcustomelement> which would technically work, but that just becomes HTMLUnknownElement and you can never register in the custom elements registry.

this issue tracker is about CSS though.

I imagine this probably isn't the place to talk about node.isCustomElement being added to the platform.

@titoBouzout
Copy link

Right, its kind of relevant because we want the same thing but as a property instead. node.isWebElement would work good. I have been linked to this thread Where should I start a thread about adding node.isWebElement to the browser?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
HTML Requires coordination with HTML people
Projects
None yet
Development

No branches or pull requests

5 participants