Skip to content
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

[css-ui] Pseudo-element for select's UA button #10717

Open
josepharhar opened this issue Aug 9, 2024 · 13 comments
Open

[css-ui] Pseudo-element for select's UA button #10717

josepharhar opened this issue Aug 9, 2024 · 13 comments
Labels

Comments

@josepharhar
Copy link
Contributor

I proposed a bunch of pseudo-elements in this issue, and I'd like to split each pseudo into a separate issue: #10462

The pseudo-element would target the <button> element in the UA shadowroot as described in the original issue as well as the draft HTML spec: whatwg/html#10548

Here are some options for a name:

  1. ::select-button
  2. ::select-fallback-button
@nt1m
Copy link
Member

nt1m commented Aug 9, 2024

The fact that you can do select { ... } to style the in-page control is pretty well established and backwards-compatible.

Maybe a stupid question, but why introduce a new ::select-button pseudo-element that would only work in newer user agents?

@nt1m
Copy link
Member

nt1m commented Aug 9, 2024

https://open-ui.org/components/customizableselect/#customizing-basic-styles

The explainer has:

<select>
  <option>one</option>
  <option>two</option>
</select>
<style>
select, select::select-fallback-button {
  font-family: monospace;
  font-size: 12px;
}
</style>

I think that is a really unfortunate developer experience to have to specify both selectors. I really think this "fallback button" should only visible to the user agent. I don't think engineering wise it's an insurmountable challenge and it preserves backwards compatibility, which is nice.

Maybe consider making the fallback button full size, but "invisible" (deferring all of its styling to the parent select):

#fallback-button {
   /* reset some button styles to make button "invisible" (potentially `all: unset` could work here too) */
   background: unset;
   border: unset;
   color: unset; /* essentially the same as inherit / currentColor in this context */

   /* make it take the full size of the in-page box */
   width: 100%;
   height: 100%;
}

Then the appearance: base UA stylesheet would put its base styles (arrow icon, border, padding, etc.) on select:-internal-uses-fallback-button or select:not(:has(> button)).

@nt1m
Copy link
Member

nt1m commented Aug 9, 2024

It's also worth noting that:

select, select::select-fallback-button {
  font-family: monospace;
  font-size: 12px;
}

doesn't actually work in older browsers, because the whole declaration will be dropped as a result of not being able to parse select, select::select-fallback-button. So you'd end up having to do:

@supports selector(::select-fallback-button) {
   // duplicate styling
}

@supports not selector(::select-fallback-button) {
   // duplicate styling
}

I think it would be really good to try to make styling on select just work directly in the fallback button case at least.

@josepharhar
Copy link
Contributor Author

Thanks for the feedback!

I like the idea of setting a bunch of properties to unset to make them inherit from the shadow host <select>, that would make the ::select-fallback-button usage as shown in the explainer unneeded.

Maybe consider making the fallback button full size, but "invisible" (deferring all of its styling to the parent select):

The way I've been designing this so far is to try to make the <select>'s box "invisible" rather than the fallback or author buttons invisible, mostly by removing borders from the <select> in appearance:base mode. This has been nice because its consistent between the cases of author provided or fallback buttons.

If we make the fallback button "invisible", then when the author provides their own button should we make that one "invisible" too? Or should we make the author apply more styles to make the <select>'s box "invisible"? For example, we could end up with the situation where by default both the <select> has a border and the author provided <button> has a border. I don't think this would ever be desirable, and ideally we wouldn't put the burden on the author to pick one of the borders and remove the other.

I'm also worried about the focus ring being rendered around the invisible fallback button inside the visible select, which would for example make the focus ring get rendered inside of the border and look wrong. I suppose that's something I could try adding a bunch of special casing for in the rendering of focus rings but I'd prefer not to try that.

Is there a way we could make the non-inherited properties that would affect the box of the <select> to all be delegated to the fallback <button> instead, like borders?

@nt1m
Copy link
Member

nt1m commented Aug 9, 2024

If we make the fallback button "invisible", then when the author provides their own button should we make that one "invisible" too? Or should we make the author apply more styles to make the 's box "invisible"? For example, we could end up with the situation where by default both the has a border and the author provided has a border. I don't think this would ever be desirable, and ideally we wouldn't put the burden on the author to pick one of the borders and remove the other.

You could put the select box appearance: base styles apply to select:not(:has(> button)) (or some internal pseudo-class which would represent when the fallback is used), then you wouldn't have conflicting styles if the developer wants to use their own button. If the developer specifies their own button, we can safely assume they want full control over the button, rather than trying to aim for backwards compatibility (which would likely be impossible in this case).

I'm also worried about the focus ring being rendered around the invisible fallback button inside the visible select, which would for example make the focus ring get rendered inside of the border and look wrong. I suppose that's something I could try adding a bunch of special casing for in the rendering of focus rings but I'd prefer not to try that.

If the fallback button has the full size of the select in-page box, it's likely not super noticeable. Though I think you'd want to defer focus to the parent select in this case, since authors who've previously defined styles for select:focus-visible would likely want them to keep working.

@nt1m
Copy link
Member

nt1m commented Aug 9, 2024

Is there a way we could make the non-inherited properties that would affect the box of the <select> to all be delegated to the fallback <button> instead, like borders?

select {
    display: contents !important;
}
 
#fallback-button {
   all: inherit;
   display: inline-block;
}

is what I can think of, but it wouldn't pass over the display value from the select.

@josepharhar
Copy link
Contributor Author

I'm starting to think that it might be better to remove the fallback UA <button> element entirely and replace it with a text node or a div containing text, which is more like how appearance:auto works.

We would then have to do some other fixes though:

  • Add custom logic to make <select> itself have popover invoking behavior for the <datalist>, but only if there is not an author-provided <button>.
  • Remove the fallback text node or div from the layout tree when there is an author-provided <button>.
  • Possibly more changes related to focus based on whether there is an author-provided <button> present?

With this in mind, I like your display:contents idea more. Thanks for the suggestion! I'll try implementing it and see what happens.

@nt1m
Copy link
Member

nt1m commented Aug 12, 2024

This is more of implementation question at this point, but I think you're better off with a div/span or a text node than my display: contents idea honestly. It does potentially pose some challenges, but it's more accurately represents what you're trying to achieve.

@fantasai
Copy link
Collaborator

select {
    display: contents !important;
}
 
#fallback-button {
   all: inherit;
   display: inline-block;
}

This seems a bit weird, why not just

fallback-button, select > button {
   display: contents;
}

?

@fantasai fantasai added css-ui-4 Current Work css-ui-5 labels Aug 13, 2024
@josepharhar
Copy link
Contributor Author

select {
    display: contents !important;
}
 
#fallback-button {
   all: inherit;
   display: inline-block;
}

This seems a bit weird, why not just

fallback-button, select > button {
   display: contents;
}

?

I tried prototyping this and there were no focus rings, so I'd have to additionally try making changes to how focus rings get rendered. I imagine there would also be other issues since this puts display:contents on the element which is actually getting focused.

This is more of implementation question at this point, but I think you're better off with a div/span or a text node than my display: contents idea honestly. It does potentially pose some challenges, but it's more accurately represents what you're trying to achieve.

I'll try prototyping this next to see what it looks like

@josepharhar
Copy link
Contributor Author

This is more of implementation question at this point, but I think you're better off with a div/span or a text node than my display: contents idea honestly. It does potentially pose some challenges, but it's more accurately represents what you're trying to achieve.

I'll try prototyping this next to see what it looks like

I started prototyping this and it looks appealing so far, but I need to finish it to make sure there aren't any gaps.

@josepharhar
Copy link
Contributor Author

I'm still working on the prototype, but so far it seems promising. I filed an openui issue to get feedback from them on this later today: openui/open-ui#1086

Proposed resolution: Don't create a pseudo-element for select's UA "fallback" button

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Sep 17, 2024
This patch removes customizable <select>'s fallback <button> element in
the UA shadowroot by replacing it with the same "InnerElement" <div>
which is used for appearance:auto.

Several supporting changes were made in order to implement this:
- Also remove ::select-fallback-button-text
- Add -internal-appearance-auto-base-select() support for the following
  properties:
  - min-block-size
  - min-inline-size
  - padding-block-start
  - padding-block-end
  - padding-inline-start
  - padding-inline-end
  - content in select::after
- Make <select> focusable again when there is no child <button> element
- Remove dependency on popover triggering code in HTMLFormControlElement
  now that we aren't always opening the popover with a <button>

This is in response to feedback here:
w3c/csswg-drafts#10717

This also addresses additional feedback I received privately that author
styles applied to the select element itself weren't applying to the
in-page portion of the element.

Change-Id: I0a833b370babe9a8ab937822a3578d839510a8fc
aarongable pushed a commit to chromium/chromium that referenced this issue Sep 17, 2024
This patch removes customizable <select>'s fallback <button> element in
the UA shadowroot by replacing it with the same "InnerElement" <div>
which is used for appearance:auto.

Several supporting changes were made in order to implement this:
- Also remove ::select-fallback-button-text
- Add -internal-appearance-auto-base-select() support for the following
  properties:
  - min-block-size
  - min-inline-size
  - padding-block-start
  - padding-block-end
  - padding-inline-start
  - padding-inline-end
  - content in select::after
- Make <select> focusable again when there is no child <button> element
- Remove dependency on popover triggering code in HTMLFormControlElement
  now that we aren't always opening the popover with a <button>

This is in response to feedback here:
w3c/csswg-drafts#10717

This also addresses additional feedback I received privately that author
styles applied to the select element itself weren't applying to the
in-page portion of the element.

Change-Id: I0a833b370babe9a8ab937822a3578d839510a8fc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5786670
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1356701}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Sep 17, 2024
This patch removes customizable <select>'s fallback <button> element in
the UA shadowroot by replacing it with the same "InnerElement" <div>
which is used for appearance:auto.

Several supporting changes were made in order to implement this:
- Also remove ::select-fallback-button-text
- Add -internal-appearance-auto-base-select() support for the following
  properties:
  - min-block-size
  - min-inline-size
  - padding-block-start
  - padding-block-end
  - padding-inline-start
  - padding-inline-end
  - content in select::after
- Make <select> focusable again when there is no child <button> element
- Remove dependency on popover triggering code in HTMLFormControlElement
  now that we aren't always opening the popover with a <button>

This is in response to feedback here:
w3c/csswg-drafts#10717

This also addresses additional feedback I received privately that author
styles applied to the select element itself weren't applying to the
in-page portion of the element.

Change-Id: I0a833b370babe9a8ab937822a3578d839510a8fc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5786670
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1356701}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Sep 17, 2024
This patch removes customizable <select>'s fallback <button> element in
the UA shadowroot by replacing it with the same "InnerElement" <div>
which is used for appearance:auto.

Several supporting changes were made in order to implement this:
- Also remove ::select-fallback-button-text
- Add -internal-appearance-auto-base-select() support for the following
  properties:
  - min-block-size
  - min-inline-size
  - padding-block-start
  - padding-block-end
  - padding-inline-start
  - padding-inline-end
  - content in select::after
- Make <select> focusable again when there is no child <button> element
- Remove dependency on popover triggering code in HTMLFormControlElement
  now that we aren't always opening the popover with a <button>

This is in response to feedback here:
w3c/csswg-drafts#10717

This also addresses additional feedback I received privately that author
styles applied to the select element itself weren't applying to the
in-page portion of the element.

Change-Id: I0a833b370babe9a8ab937822a3578d839510a8fc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5786670
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1356701}
@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-ui] Pseudo-element for select's UA button, and agreed to the following:

  • RESOLVED: do not add a pseudo-element for the user-agent fallback select button
The full IRC log of that discussion <chrishtr> jarhar: I finished implementing the removal of the buttons and replacing with div w/text in Chromium. Then fonts are inherited well. So I think it works well.
<chrishtr> jarhar: propose not to create a pseudo-element for the select button
<fantasai> +1
<ntim> +1
<chrishtr> RESOLVED: do not add a pseudo-element for the user-agent fallback select button
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
4 participants