[select] Don't reuse slot="" and ::part(); behavior="" is also strange
domenic opened this issue · 40 comments
slot="" and ::part() are used for custom elements. They are a separate namespace for authors to use.
Native HTML elements get customized via normal child elements and pseudo-elements:
<summary>
for<details>
,<option>
and<optgroup>
for<select>
,<legend>
for<fieldset>
, ...::marker
for<details>
,::backdrop
for<dialog>
,::placeholder
for<input>
, etc. (This is maybe related to #645.)
Similarly, your use of a semi-generic behavior=""
attribute, which only has meaning within a certain parent context but can be used on any arbitrary element, is not idiomatic to HTML either. Is there any way to replace that with an idiomatic child-element pattern?
Thanks for your feedback! I see what you mean, especially with your details and summary example.
What if we replaced all of the slot and behavior attributes with new elements?
<div popover=auto slot=listbox behavior=listbox>
would become<listbox>
<button slot=button behavior=button>
would become<selectmenubutton>
or something. I don't think we can necessarily just use<button>
because you might want to use<button>
elements in other parts of the selectmenu.<span slot=selected-value behavior=selected-value>
would become<selectedvalue>
<span slot=marker behavior=marker>
would become<marker>
, or maybe we could replace it entirely with a pseudo-element...?
This would align better with the HTML spec, but may also reduce the customizability of selectmenu, for example by not providing a way to opt out of behaviors - not sure how important this actually is for customizability though.
I'm likely missing historical context on this. I'd like to talk about it at the next meeting
What if we replaced all of the slot and behavior attributes with new elements?
I think this would be ideal. I look forward to hearing back what others say at the meeting, but I think this should be the starting position, and any deviations from it should be considered quite carefully. (It feels like instead the current starting position was some sort of custom element library.)
This would align better with the HTML spec, but may also reduce the customizability of selectmenu
I'll need to think about this a bit and run through a variety of use cases to determine the implications of this recommendation as this is actually my key concern and why we landed where we did. Looping in @jh3y since he's probably built the most selectmenu
demos and would be able to determine if this would break his customizations or not.
slot="" and ::part() are used for custom elements. They are a separate namespace for authors to use.
Can you comment more on this? slot
and part()
aren’t just for custom elements, right? They’re for shadow DOM, which the <selectmenu>
contains. Part of what I liked about this proposal was that it isn’t co-opting these attributes for a different purpose, it is directly using them. I.e. the slot attribute actually slots that element into the UA shadow root. And ::part() exposes the parts. This would be the first native element with a well defined shadow structure designed for direct part replacement like this. But I think the way this works is exactly the same “namespace” as custom elements that use shadow DOM.
A nice thing (IMHO) about using slotting attributes is that a semantically appropriate element such as a <button>
or <input>
can be used, rather than a new element that presumably always acts like a button?
Can you comment more on this?
slot
andpart()
aren’t just for custom elements, right? They’re for shadow DOM
Sorry, I mispoke, you're right. They're for shadow DOM. But, specifically by shadow DOM, I mean they're for DOM trees created by authors with attachShadow()
(or declarative shadow DOM).
which the
<selectmenu>
contains.
<selectmenu>
does not (or at least should not) contain shadow DOM, in the sense of "something accessed and created through the normal shadow DOM APIs". I expect that if it's a native HTML element, it might have a sort of "user agent shadow root", like various implementations have chosen to use when implementing controls like <input type=date>
, <details>
, or <select>
. But this is just an implementation detail, and should not interfere with the normal web developer APIs. There should be no shadowRoot
property; slot=""
and ::part()
should not get their meaning changed by the presence of these elements; etc.
This would be the first native element with a well defined shadow structure designed for direct part replacement like this.
<details>
is arguably such an element, as is <select>
itself. Maybe even <li>
, with its ::marker
being the replace-able part. The point is, the choice of underlying technology to implement those "replaceable slots" is an implementation detail. Chromium might have chosen to use shadow DOM for <selectmenu>
, but that implementation-specific technology choice must not leak into the specification and start interfering with web-developer-facing technology like slot=""
or ::part()
.
A nice thing (IMHO) about using slotting attributes is that a semantically appropriate element such as a
<button>
or<input>
can be used, rather than a new element that presumably always acts like a button?
Again, I don't think existing examples bear this out. <summary>
is not exactly like a button. <button>
s can have arbitrary behavior, but <summary>
always expands/collapses its <details>
element. I think that's the same intention for <selectmenubutton>
as explained in #702 (comment) .
I need more time to collect pros/cons and limitations of slots/behaviors vs elements in order to present in a meeting, so I am removing the agenda+ label and will re-add it when I am ready. Anyone can continue to discuss here in the meantime.
Just chiming in from a web developer perspective obviously I understand there's trade-offs with each API.
I think I prefer treating it as a customizable shadow root rather than like the old style html elements. The main concern seems to be this isn't how HTML behaves currently but isn't that the problem that open-ui is trying to solve in that there isn't a proper specification for structure and stylability?
Take the file input for example we can currently customise the selector button using a (only fairly recently) standard pseudo element but we can't for example remove the label entirely or customise its text even. This would be better as a more defined shadow root like selectmenu.
If a proper structural spec appears for HTML elements then the worries about exposing implementation details (presumably for forwards compatibility reasons) mostly go away?
Also adding a new CSS pseudo element or actual html element for every single customisable part of each html element doesn't seem like a great design to me. Even adding the search html element required accessibility tools to update and various other software changes. Adding loads more elements each with their own contextual semantics seems like it might end up in a place where those kinds of tools are constantly playing catch-up?
I'm not sure there's a appreciable practical difference in favour of using ::part()
/slot=
. Domenic is talking about avoiding the ::part
and slot
syntax, as it should be free to live within the realm of user-authored ShadowDOM, and the browser shouldn't introduce built ins using this as it is yet another surface for potential webcompat issues. In other words ::part()
/slot=
should be like data-
attributes, and -
in element names; an effective safe ground for userland, with a handshake agreement from specs not to collide.
::part()
is an ergonomic tradeoff between webcompat safety and CSS complexity at the cost of developer ergonomics. Those concerns aren't present when using "bare" pseudo selectors. Instead of ::part(foo)
, browsers can introduce syntax like ::foo
without webcompat issues, without the ergonomic tradeoff of ::part()
and without the same CSS complexity concerns (it will be a well defined extension to CSS rather than a custom userland one).
Likewise slot=
is a declarative mechanism for ShadowDOM authors to allow re-arranging of nodes to fit within a template structure. The browser doesn't need this as it can construct these based on other serialisable steps, such as the tag name (which userland can do, but it requires JS).
The rest of the mechanics are identical; older elements (like <input>
) lacking well defined structural markup needn't set a precedent. Newer elements like <details>
/<summary>
can instead.
The concerns of adding more pseudo selectors vs using part seem rather unimportant; pedagogically speaking webdevs will have to learn either one; if I want to style a marker learning to target either ::part(marker)
or ::marker
is essentially the same mental space, except for those who haven't had exposure to authoring ShadowDOM would need to learn new concepts like ::part()
.
The other concern of using ::part()
/slot
is that it makes it harder to differentiate, within a CSS file, which declarations drive userland and which drive the browser. A declaration of ::marker {}
has certain guarantees about the elements it will style, and the safety & cadence of which new elements will end up being targeted by that selector. The same is not true for ::part(marker) {}
which could conflict with arbitrary elements.