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

[invokers] - how to style invoking element based on Invoker state? #622

Open
scottaohara opened this issue Oct 13, 2022 · 18 comments
Open
Labels
invokers popover The Popover API

Comments

@scottaohara
Copy link
Collaborator

scottaohara commented Oct 13, 2022

As per the discussion on #610 we briefly discussed how there is not presently a way to style the invoking element of a popup based on the current state.

Presently, if building something like this with HTML / ARIA today, one could use <button aria-expanded=true|false> and use the ARIA attribute as the hook. It seems this is something the invoking element for a popup should/could support (whether an attribute needs to be reflected in the DOM, or a pseudo class (:expanded and :collapsed to match current ARIA conventions? :opened and :closed), or other e.g., .indeterminate for checkboxes in HTML. Not implying preference on any of those, merely listing the ways to do this that quickly come to mind.

cc @mfreed7

@hidde
Copy link
Contributor

hidde commented Oct 15, 2022

As we resolved on applying :open to <selectmenu> (to which :close was added) in #547 … would it make sense (and technically possible?) to have :open apply to all popup invoking elements?

@mfreed7 mfreed7 added popover The Popover API agenda+ Use this label if you'd like the topic to be added to the meeting agenda labels Oct 25, 2022
@jh3y
Copy link
Collaborator

jh3y commented Nov 10, 2022

Jus' throwing some extra things in here for thought:

  • Although not the prettiest you can do this with :has but that does open up a maintenance issue.
body:has([id=pop]:open) [popovertoggletarget=pop] {
  /* Open styles */
}
  • Are there many examples out there currently of popovers that have a toggle button aside from selectmenu or something involving a menu like interaction?
@scottaohara
Copy link
Collaborator Author

scottaohara commented Nov 10, 2022

Sub-navigations, popup disclosure widgets / toggle tips that may contain info, links, buttons.

those should be rather common in Regards to needing popup behavior. Maybe those are what you meant by something with a menu like interaction?

@jh3y
Copy link
Collaborator

jh3y commented Nov 10, 2022

Then, if some sort of open attribute could be used, I'm imagining it would be something like popoveropen based on other attribute names, this might in turn solve #631. The existence of the attribute could potentially drive the show/hide behavior and means we don't get something like

<div popup popupopen popupdefaultopen>

That reminds me of React when I'm having to define defaultValue 😅

@jh3y
Copy link
Collaborator

jh3y commented Nov 10, 2022

There's maybe a more dynamic way:

<div class=toggle-tip-container toggle-container>
  <button popovertoggletarget=pop>
    Toggle
  </button>
  <div popover id=pop>Popover</div>
</div>
[toggle-container]:has([popover]:open) button {
  /* Do something to my button! */
}
@css-meeting-bot
Copy link

The Open UI Community Group just discussed [popup] - how to style invoking element based on popup state?.

The full IRC log of that discussion <gregwhitworth> Topic: [popup] - how to style invoking element based on popup state?
<gregwhitworth> github: https://github.com//issues/622
<JonathanNeal> masonf: so this is a question about invoking a popover.
<scotto_> q+
<jhey> q+
<JonathanNeal> masonf: right now we don’t have a way to style the anchor for a popover by the popover state
<gregwhitworth> ack scotto_
<JonathanNeal> scotto_: looking at this again, `:has` doesn’t really solve the issue.
<JonathanNeal> scotto_: would `:open` go the button or on the actual popover?
<JonathanNeal> masonf: in the example, the selector is ‘clever’ there.
<gregwhitworth> q+
<flackr> q+
<JonathanNeal> masonf: (continues explaining this complicated selector)
<JonathanNeal> jhey: it was confusing, because there was a typo in the code, and I’ve just edited it.
<flackr> q-
<JonathanNeal> scotto_: so in a very round about way, and as long as there are no typos, there’s a way to do it.
<JonathanNeal> q+
<JonathanNeal> jhey: (explains the trick a bit further)
<gregwhitworth> ack jhey
<JonathanNeal> jhey: but do we expect people to write it all the time?
<JonathanNeal> jhey: I don’t know, is it going to be confusing?
<gregwhitworth> ack dbaron
<JonathanNeal> dbaron: to me, this sort of feels like a combinator in CSS.
<JonathanNeal> dbaron: except — and I think I proposed this before in the CSSWG and lost — I think there may be value in writing this sort of combinator like a functional pseudo-class.
<JonathanNeal> dbaron: the way I would want to write this is, I think, like a pseudo class taking a selector argument.
<JonathanNeal> dbaron: so, if you could write `:associated-popup()` that takes a selector.
<JonathanNeal> dbaron: this became the column combinators, which I don’t think anyone has implemented.
<dbaron> https://drafts.csswg.org/selectors-4/#the-column-combinator
<jhey> q+
<JonathanNeal> gregwhitworth: I thought you might be bring up the scenario we brought up, where people started wrapping; because they wanted something to change styling based on a state change to something associated with an element.
<JonathanNeal> gregwhitworth: if I’ve created a button that I know is associated with a thing, then I want to style it by that association. But in that scenario, people would wrap everything to maintain the state.
<gregwhitworth> ack gregwhitworth
<JonathanNeal> dbaron: jhey’s example with `:has()` is the most inefficient way to use `:has()` possible, and I don’t think we want to encourage it.
<JonathanNeal> masonf: lots of blog posts have this.
<JonathanNeal> dbaron: but `body:has()` is really bad.
<JonathanNeal> masonf: they use `:root:has()`.
<JonathanNeal> jhey: one really quick workaround is to wrap them in a common thing.
<JonathanNeal> jhey: it’s better than the `body:has()`.
<gregwhitworth> ack JonathanNeal
<gregwhitworth> JonathanNeal: that's a solution, similar to what you said is the scenario
<gregwhitworth> JonathanNeal: earlier when we discussed defaultopen - we discussed solving a harder problem
<gregwhitworth> JonathanNeal: what we are reaching for here is a solution that invites parity with other things
<gregwhitworth> JonathanNeal: as we have discussed this, oh good - something aria-controls would be useful for
<gregwhitworth> JonathanNeal: something to associate my disclosure popup where I don't have to use IDs
<gregwhitworth> JonathanNeal: this is already very complicated in HTML
<gregwhitworth> JonathanNeal: I would hope that we would avoid it
<gregwhitworth> JonathanNeal: I've worked with many react libraries where dynamic IDs would try to be kept to keep up with the html
<gregwhitworth> q+
<gregwhitworth> JonathanNeal: if the targeting situation should be tackled then we should tackle it holistically with any other association
<gregwhitworth> JonathanNeal: an aria association, and that pattern can solve a myriad of usecases
<gregwhitworth> ack jhey
<JonathanNeal> jhey: I don’t think I need to say anything now.
<masonf> q+
<JonathanNeal> gregwhitworth: the reason I raised what I raised because we got bombarded by this because we had to generate unique element names, but I am concerned with boiling the cone.
<JonathanNeal> gregwhitworth: *boiling the ocean
<JonathanNeal> gregwhitworth: that’s where I say: let’s just do the magic for them.
<JonathanNeal> gregwhitworth: so `button:open` would work when the popover is open.
<JonathanNeal> gregwhitworth: I could already see the CSSWG getting mad about that.
<JonathanNeal> gregwhitworth: I’m trying to find a middle ground.
<gregwhitworth> ack gregwhitworth
<gregwhitworth> ack masonf
<JonathanNeal> gregwhitworth: I remember in the other scenario, engines mentioned that it has a lot of complexity.
<JonathanNeal> masonf: maybe there’s a more generic feature to be proposed.
<gregwhitworth> ACTION: masonf to write up potential for associated complex CSS selector
<gregwhitworth> Zakim, end meeting
<Zakim> As of this point the attendees have been gregwhitworth, scottkellum, JonathanNeal, flackr, una
<Zakim> RRSAgent, please draft minutes
<RRSAgent> I have made the request to generate https://www.w3.org/2022/11/10-openui-minutes.html Zakim
<JonathanNeal> matthias: I love what you are doing. Now days we might call it “low code”. We did something 3 or 4 years ago, and we’re using it today. It would enable me to try it once with Material UI and then another system.
<Zakim> I am happy to have been of service, gregwhitworth; please remember to excuse RRSAgent. Goodbye
<JonathanNeal> matthias: but what we were missing is what you are providing.
<JonathanNeal> matthias: so I was wondering; what is the DSL for this? Is it HTML? Or something else?
<JonathanNeal> matthias: Currently, we are using YAML.
<JonathanNeal> gregwhitworth: We are using HTML is the markup language for describing the different parts.
<JonathanNeal> gregwhitworth: It will be described in text, that is ultimately defined in HTML.
<JonathanNeal> gregwhitworth: Mind you, some things will be for CSS.
<JonathanNeal> gregwhitworth: Ultimately those will be spec text.
<JonathanNeal> gregwhitworth: We don’t have it simplified down to a schema org type setup.
<JonathanNeal> gregwhitworth: It would be nice if we did.
<JonathanNeal> gregwhitworth: DM me more questions.
@mfreed7
Copy link
Collaborator

mfreed7 commented Nov 11, 2022

So I notice the action item in the notes above for me. I'm a bit unclear on the exact mechanics of the proposal, and in fact I heard two variations, one from @dbaron and one from @gregwhitworth. I just tried to write them both up, and I realized I'm not sure I completely understand them. Both were essentially (functional?) pseudo elements that could be used to associate a popover invoker with its popover, and also perhaps a label with its form control. In the popover case, the idea is to be able to style the button based on the :open state of its associated popover. In the form control case, style the <label> based on the :hover state of its form control.

@dbaron and @gregwhitworth can you please fill in the gaps above?

@gregwhitworth
Copy link
Member

What mine was that in EdgeHTML we propogated state to the associated element. Using the historical example:

HTML
===========
<label for=foo>My Label</label>
<button id=foo>Hello</button>

CSS
===========
label:hover {
    background: blue;
}

In order to achieve this today, authors wrap the button with the label which is akin to @jh3y CSS approach using has.

So I was merely stating that we should define the anchor attributes to propagate style psuedo class state to the button that has an association.

@dbaron was referring to a complex constructor or function that would allow association to be called. I'd need to see the definition of this to ensure that dynamic solutions can be covered.

@gregwhitworth gregwhitworth removed the agenda+ Use this label if you'd like the topic to be added to the meeting agenda label Nov 15, 2022
@mfreed7
Copy link
Collaborator

mfreed7 commented Dec 1, 2022

I like this idea of allowing easy(er than :has) styling of a triggering element, based on the state of the triggered popover. However, I think a) it might be a more general feature (see above), and b) I think it can almost surely be added later without breaking anything. For these two reasons, I'm going to mark this as a "V2" feature. Hopefully ok with folks.

@github-actions
Copy link

There hasn't been any discussion on this issue for a while, so we're marking it as stale. If you choose to kick off the discussion again, we'll remove the 'stale' label.

@github-actions github-actions bot added the stale label May 31, 2023
@lukewarlow lukewarlow added invokers and removed stale labels Nov 18, 2023
@lukewarlow lukewarlow changed the title [popup] - how to style invoking element based on popup state? Nov 18, 2023
@lukewarlow
Copy link
Collaborator

Gonna commandeer this issue to discuss styling invokers based on Invokee state more generally than just popover.

@lukewarlow
Copy link
Collaborator

w3c/csswg-drafts#9547 contains some discussion regarding this.

@scottaohara
Copy link
Collaborator Author

scottaohara commented Nov 21, 2023

it is probably a good idea to have a more generic invoked (true) / not invoked (false) styling hook, rather than try to tap into any explicit state (e.g., 'pressed' vs 'expanded' vs custom / no clean matching semantics for a pseudo class) for styling. Especially since the expanded/collapsed state is only applicable to some, and i still have doubts about whether automatically exposing a pressed/not pressed state for play/pause makes sense - since people are more likely to change the labels of those, and we don't want a label AND state change to occur.

@bkardell
Copy link
Collaborator

it is probably a good idea to have a more generic invoked (true) / not invoked (false) styling hook

Is it invocation related or state related? Like, imagine we had a silly interface:

<button id="A" invoketarget="my-video" invokeaction="playpause">Play/Pause</button>

<video id="my-video"></video>

<button  id="B" invoketarget="my-video" invokeaction="playpause">Play/Pause</button>
  • If the video autoplayed or something: Do either of the invokers light up?
  • Which is "invoked" here - play, or pause - or does it depend on whether the video was already playing?
  • If you click button A, and we determine it should match - does B also match?
@scottaohara
Copy link
Collaborator Author

i didn't anticipate this working (well) without being state related. maybe that's a bad assumption on my part, but if the video was autoplaying i would have anticipated both those buttons reflecting the 'playing' state of the video - so 'invoked = true' for the purposes of stying (yes i know it's not invoked by the user - but also the alternative is rubbish UX if not reflecting the state of the video). activating either button would cause the video to pause, and both buttons would need to refelct this state and expose an invoked false style hook.

@keithamus
Copy link
Collaborator

I guess today, one might use :has() to solve this problem for simple cases:

<style>
  body:has(video:playing) button .play-label,
  body:has(video:paused) button .pause-label {
    display:none
  }
</style>
<button id="A" invoketarget="my-video" invokeaction="playpause">
  <span class="play-label">Play</span>
  <span class="pause-label">Pause</span>
</button>
<video id="my-video"></video>

I wonder if we can leverage the same inverted relationship where the button can query state about its linked idref?

<style>
  button:invoketarget-linked(video:playing) .play-label,
  button:invoketarget-linked(video:paused) .pause-label {
    display:none
  }
</style>
<button id="A" invoketarget="my-video" invokeaction="playpause">
  <span class="play-label">Play</span>
  <span class="pause-label">Pause</span>
</button>
<video id="my-video"></video>
@lukewarlow
Copy link
Collaborator

Yeah Tim mentioned an ':invoketarget()' selector as an idea. Invalidating could be interesting but no more difficult than has or others.

Copy link

There hasn't been any discussion on this issue for a while, so we're marking it as stale. If you choose to kick off the discussion again, we'll remove the 'stale' label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
invokers popover The Popover API
9 participants