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

Add the :open and :closed pseudo-selectors #10126

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

josepharhar
Copy link
Contributor

@josepharhar josepharhar commented Feb 7, 2024

These pseudo-selectors are defined in CSS here: https://drafts.csswg.org/selectors-4/#open-state

These match on details, dialog, and select elements since they can be in an open or closed state. When they are open they match :open, and then they are closed they match :closed.

(See WHATWG Working Mode: Changes for more details.)


/semantics-other.html ( diff )

source Outdated
</li>

<li><p>If <var>element</var> is a <code>select</code> element and <var>element</var> is being
rendered as a button with a popup and the popup is open, then return true.</p></li>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is very vague, but the select element as specced never mentions that it can be an in-page listbox or a button with a popup. I figure that it makes sense to match neither :open or :closed when it is being rendered as an in-page listbox with no popup, but in any case we need some way of saying that the popup is open.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't the rendering section have something to reuse for this? If we're going to depend on rendering I feel like we'd want to at least link to a shared concept.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah it is defined in rendering! https://html.spec.whatwg.org/multipage/rendering.html#list-box

However, I don't think the definition reflects browsers because it says that having the multiple attribute means that it renders a list box, but in iOS safari and android chrome having the multiple attribute renders as a drop-down box.

Maybe I could fix that separately?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now I've referenced the "drop-down box" definition from rendering

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #8189

@josepharhar
Copy link
Contributor Author

@nt1m maybe you're interested in this?

Copy link
Member

@annevk annevk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tackling this!

source Outdated Show resolved Hide resolved
source Outdated
<p>If <var>element</var> is a <code>details</code> or <code>dialog</code> element:</p>

<ol>
<li><p>Return true if <var>element</var> has the <code data-x="attr-dialog-open">open</code>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You cannot point to a specific open attribute if it's about two distinct ones. Using data-x="" should suffice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I separated them and referred to specific open attributes. Look good?

source Outdated
</li>

<li><p>If <var>element</var> is a <code>select</code> element and <var>element</var> is being
rendered as a button with a popup and the popup is open, then return true.</p></li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't the rendering section have something to reuse for this? If we're going to depend on rendering I feel like we'd want to at least link to a shared concept.

source Outdated
<dt><dfn selector><code data-x="selector-closed">:closed</code></dfn></dt>
<dd>
<p>The <code data-x="selector-closed">:closed</code> <span>pseudo-class</span> must match any
element that <span>matches the closed selector</span>.<p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be inlined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I combined the paragraphs, does it look good?

source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
@domenic
Copy link
Member

domenic commented Feb 9, 2024

These match on details, dialog, and select elements since they can be in an open or closed state.

Has it been discussed whether they should match other pickers besides select, like color pickers, date pickers, etc.? Basically all the things that showPicker() triggers.

@josepharhar
Copy link
Contributor Author

Has it been discussed whether they should match other pickers besides select, like color pickers, date pickers, etc.? Basically all the things that showPicker() triggers.

That sounds great! I just used it on the elements that the css spec listed, but I don't see any reason why we shouldn't support <input> as well.

I think this might get nuanced even more than <select> since some browsers have popups for date/time input types and others don't. How should I proceed?

@annevk
Copy link
Member

annevk commented Feb 10, 2024

I wonder if we can turn "If no such UI applies to element" into a rendering concept and branch :open/:closed on that. That would also allow you to detect picker support. This should not introduce a new fingerprinting vector as it will be 1:1 with the user agent.

cc @nt1m @pxlcoder @lukewarlow

@lukewarlow
Copy link
Member

As far as I understand the reason showPicker() doesn't return a success boolean was because browsers explicitly didn't want to "leak" the information about whether they show a picker on these elements, I think it was for forwards compatability so they'd be free to add them in future without people relying too much on them existing or not in a given UA.

I personally think it would be great if we could apply these to those elements and support the feature detection for showPicker().

source Outdated
<li><p>A <code>dialog</code> element which has the <code data-x="attr-dialog-open">open</code>
attribute.</p></li>

<li><p>A <code>select</code> element which is a <span>drop-down box</span> whose drop-down box
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be irelevant for the HTML spec but Firefox for Android renders a multiple or size select as a list box but also opens a modal when clicked, should that match :open?

Also Chromium for Android renders selects as a conventional drop down style but opens a modal not a drop down, should that match :open?

Just trying to clarify because the "drop-down box" terminology is ambiguous as first glance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah if it opens as a modal when clicked then I don't see why it shouldn't match :open

@annevk
Copy link
Member

annevk commented Feb 19, 2024

If it was decided that showPicker() shouldn't reveal that information we should not make :open and :closed applicable to those elements until we decide otherwise. It seems reasonable to explore further as a follow-up though.

@josepharhar
Copy link
Contributor Author

As far as I understand the reason showPicker() doesn't return a success boolean was because browsers explicitly didn't want to "leak" the information about whether they show a picker on these elements

I'd be interested to hear more about this, is there a conversation you can point to?

@lukewarlow
Copy link
Member

I'd be interested to hear more about this, is there a conversation you can point to?

Absolutely, so there's an open issue regarding lack of feature detection for showPicker() here and that links to a TAG design review comment here

It seems the lack of support detection was the hang up that lead to an unsatisfied resolution in TAG.

My earlier remark that "browsers" didn't want to leak might be a mischaracterisation upon further reading. But the sentiment is the same, it was concluded that it was an undesirable compat trade off.

@josepharhar
Copy link
Contributor Author

Absolutely, so there's an open issue regarding lack of feature detection for showPicker() #7790 and that links to a TAG design review comment w3ctag/design-reviews#688 (comment)

Thanks! @domenic do you think these issues still apply with this pseudo class?

@domenic
Copy link
Member

domenic commented Feb 22, 2024

Thanks! @domenic do you think these issues still apply with this pseudo class?

It depends exactly how they're defined. Consider a case like <input type=password> where browser A shows a picker and browser B does not show a picker. If we define this as matching :closed in browser B, then the issues do not occur: the web developer cannot write code that works differently in browser A vs. B. Whereas if we say that neither :open nor :closed match in browser B, then the web developer can easily write code that works differently in the two browsers, e.g. they might give only the correct styling to browser A because they put the correct styling in #my-input:closed { ... }.

Similarly, if we go with the "neither :open or :closed matches no-picker controls" model, then browser B adding picker support in one release would potentially cause new styles to apply, which is a compat risk for browser B.

That said, I don't feel that the interop and compat issues with revealing the picker-UI-or-not status of a control are blocking. I think they're reason to be cautious, but if all the implementers in the room are willing to eat those interop and future-compat costs, then from a HTML editor perspective, I have no objection.

@annevk
Copy link
Member

annevk commented Mar 4, 2024

I suppose that essentially argues for making :closed match all elements, or at least all elements that might have a picker UI. @whatwg/css does that seem reasonable?

@lukewarlow
Copy link
Member

Following up on this another place where we'd potentially like to do something that exposes picker UI existence is with invokers. If we were to add showPicker actions to invokers then it would seem logical (though I'm no expert so this might be wrong) that it exposes an aria-expanded state based on the inputs picker state?

If aria-expanded should be added it would be unfortunate if we couldn't because of this compat risk (though admittedly it's not currently detectable in code so maybe it's fine?)

@lukewarlow
Copy link
Member

Something I've just thought of. Would it be worth exposing this on datalist elements? They're kind of input pickers but also they're a separate element so idk if input:open matching necessarily makes sense for a datalist?

@josepharhar
Copy link
Contributor Author

Something I've just thought of. Would it be worth exposing this on datalist elements? They're kind of input pickers but also they're a separate element so idk if input:open matching necessarily makes sense for a datalist?

I feel like input:open makes more sense than datalist:open since we are planning on doing select:open rather than select::picker(select):open

@lukewarlow
Copy link
Member

@josepharhar
Copy link
Contributor Author

I suppose that essentially argues for making :closed match all elements, or at least all elements that might have a picker UI. @whatwg/css does that seem reasonable?

I think that making :closed match "all elements" makes sense based on domenic's explanation for compat. I added another line for input elements and said that they should always match either open or closed. I also made all select elements match either open or closed regardless of whether they have list-box rendering or not.

@lukewarlow
Copy link
Member

Is one possibility to ship :open and not :closed initially? Making :closed match things that can never be open feels odd.
And would essentially make it :not(:open) in which case do we even need :closed? Like we don't have a :popover-closed because it's the inverse of :popover-open.

Copy link
Member

@annevk annevk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Luke that starting out with just :open is better, but we should run that by the CSS WG.

Comment on lines +74561 to +74565
<li><p>A <code>select</code> element which is a <span>drop-down box</span> whose drop-down box
is open.</p></li>

<li><p>An <code>input</code> element which supports a picker popup and whose picker popup is
open.</p></li>
Copy link
Member

@annevk annevk Oct 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have some shared language (ideally in terms of <dfn>) with showPicker() here. I.e., #10126 (comment), but I no longer think it would make picker support detectable if the condition is "supports a picker and picker is open".

@bramus
Copy link

bramus commented Oct 11, 2024

Is one possibility to ship :open and not :closed initially? Making :closed match things that can never be open feels odd. And would essentially make it :not(:open) in which case do we even need :closed? Like we don't have a :popover-closed because it's the inverse of :popover-open.

Just dropping this as an FYI: :read-only is defined as :not(:read-write), and that shipped – https://html.spec.whatwg.org/multipage/semantics-other.html#selector-read-only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

6 participants