openui / open-ui

Maintain an open standard for UI and promote its adherence and adoption.
https://open-ui.org
Other
3.58k stars 191 forks source link

[Popover] Should a popover have the ability to be opened by default? #771

Open brechtDR opened 1 year ago

brechtDR commented 1 year ago

For the moment, I think there isn't a way to show a popover by default (on page load) in Chrome Canary

This could be handy for example to show a toast on page load which could be closed afterwards.

I mimic this behaviour by adding some JS in the following demo. But could be handy if I could just add "popover-open" as an attribute.

(scroll the page for to see the toast pop up, I'm combining this with scroll-driven-animation, which would be a cool thing to do)

https://codepen.io/utilitybend/pen/vYQLZEz

I can't seem to recall if this was discussed before.

scottaohara commented 1 year ago

this was discussed before, but from what I recall mostly in the scope of how this wouldn't make much sense for auto popovers, since - at the time it was discussed, those still had the behavior of auto-dismissing and would have had a high probability of hiding for anyone using a keyboard attempting to navigate the web page.

with that said, i suppose it's worth re-discussing since that behavior has changed, though i'm still a bit wary about the idea of popovers being open by default - particularly non-manual ones.

I'm also a bit unsure about the actual use case of needing this for a toast notification - being that I'd expect a toast notification to generally be triggered by a user action, and thus would already be reliant on JavaScript to display the appropriate message. Even for a use case like a cookie-banner (likely a non-modal dialog, as should arguably be a toast notification message) where one might want that to appear by default on page load - that too seems like something that would generally be reliant on JS to display or not.

But, please don't let my skepticism be mistaken for being against the idea. I'm just looking for use cases that would justify the need for this, when at least the majority of the ones I can think up (and it's still early here so i might need more coffee) with would require JS (or likely not even be a popover - that is still an option too. not everything has to be a popover :)) to accomplish anyway.

brechtDR commented 1 year ago

Thank you for commenting. I totally agree that this probably isn't the most needed thing as it could be achieved with JS. But it's a typical example of "you don't need it, until you do".

One other thing that comes to mind (as you noted as well) are GDPR cookie banners, I always wondered if these should have a dialog role for example or could be something different, so thank you for clarifying that. (In current implementations, they're mostly dialogs or not accessible at all to be honest).

Or how about those "tour" popovers, used to highlight features on platforms where you want the initial one to open right away.

The biggest benefit of having this is that you could easily re-trigger those popovers from a button if the user decides to close them right away. Without having to create a mixture between html triggers and JS triggers. That sounds pretty powerful. But agreed, they mostly have some JS written behind them to set the cookies for example.

Also agree that a default open state is mostly useful for manual popovers as auto popovers would just close right away after another interaction on the screen has been made.

Another benefit is that you can do this with dialogs by adding "open". So why not on popover? I can understand people asking that question in the future. Developers love consistency. But of course it shouldn't be implemented just for that sake.

All this aside, when it comes to implementation, it could be as straight forward as adding "popover-open" as an attribute.

Small update on the potential Combined with a lot of new CSS features, If we were to allow triggers on a dialog element (which is another issue already) and do the same for popover, we could potentially reduce the JS of this example to only handling the form submit.

https://codepen.io/utilitybend/pen/OJayqLY

gregwhitworth commented 1 year ago

@brechtDR please review #631 since it has the historical context and let me know if you want to re-visit the discussion after reviewing the threads on WHATWG and the minutes in 631.

scottaohara commented 1 year ago

that's not a good candidate for a 'toast'. it likely should be a non-modal dialog if not a fully modal dialog due to the fact it'd be difficult for someone to know how to get to it, consistently, otherwise. and the fact that one can't dismiss it without having to move focus to it would mean it'd be a prime candidate to fail wcag 2.2's focus obscured (minimum) criterion.

brechtDR commented 1 year ago

Agreed on my example not being the best use case here.

I might get back on that. But first I wanted to share why I think it could be reopened after reading up on the issue mentioned by @gregwhitworth

Some of the things that complicated the whole thing was animating from/to display none this has been tackled by the csswg Also the naming was hard especially in combination with dialogs and details elements, but those had several other related topics already.

There is a mention about consistency with the dialog element using JS, this is where I believe things are becoming hard to understand as in, "dialog can do this, popovers can't" (or the other way around)

Working on consistency is happening already:

There are differences between a dialog and a popover, but we're already laying the accessibility part in the hands of developers for a lot of use cases.

So why shouldn't a popover have the ability to be open by default just as with a dialog? This could be for showing a hint at pageload with light dismiss, and could - potentially - be handled with an aria-live attribute. (? question ?)

Is it the biggest use case out there? Probably not. But it could remove some confusion and learning curve if a dialog as well as a popover could have a default open state.

I'd love to hear some other opinions on this, but wanted to make sure we didn't just dismiss it completely without some after thought.

mrksbnch commented 1 year ago

There are use-cases where popovers should automatically open if you open a particular URL. Imagine that you are building an interface that shows a list of all users when you visit "/users". To edit one of these users, e.g. their first or last name, you want to show the <form> in a popover.

You can use popovertarget (or JavaScript) to open the popover and use something like history.pushState to change the URL to e.g. "/users/edit/:id" (where ":id" is an ID that uniquely identifies a user). When going directly to one of these URLs, e.g. "/users/edit/:id", you want to open the popover by default. Currently, the only way to achieve this is to use JavaScript which feels counterintuitive for a native HTML element, especially if the rest of the page works just fine without JavaScript.

github-actions[bot] commented 8 months ago

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.

kizu commented 8 months ago

One thing to think about: recently there were discussions about allowing to control the open state of the <details> through CSS: https://github.com/w3c/csswg-drafts/issues/9879 with the following resolutions from CSSWG:

RESOLVED: Expose the <details> contents slot as either a pseudo or a ::part, as decided in a joint meeting with WHATWG RESOLVED: We desire to have no restrictions on the stylability of the display of <details> and <summary>

I imagine, it might be worth considering the same for popovers.

lukewarlow commented 8 months ago

I have concerns with allowing you to "open" a popover with CSS. You can already force it to display block but that doesn't toggle the aria expanded state for example.

That being said I do think we should allow default open popovers.

Westbrook commented 8 months ago

Being able to open a popover with CSS might also mean that you could make an element a popover with CSS. If you could do that then you could make a :before a popover, open it on hover of the root element and then anchor position it as a super :focus-visible loupe that beat all CSS clipping and stacking, which would be pretty OK in my book....

ITenthusiasm commented 7 months ago

So from some of the use cases that I'm seeing (which also seem to coincide with some of mine), I'm wondering if what's really coming out is a desire to have something that lets developers: 1) Make the rest of the page inert (like modal dialogs), and 2) Put something in the Top Layer.

In my view, those are some of the strongest features of the <dialog> element. The ability to force the rest of the page to be inert basically eradicates all of the JavaScript needed to manage focus properly. And the ability to put something in the Top Layer removes all concerns that any developer-made "backdrop element" or "dialog/popover content" fails to span the entire page and/or appear above everything else.

I agree that the toast scenario doesn't quite seem to work here. But @mrksbnch's use case is actually something along the lines of what I was thinking of. The UX could technically be achieved without a popover if we wanted everything to work without JS. We'd just need to put the <form> that was mentioned above everything else on the page with CSS. The only problem is that we can't restrict focus to a single part of the page without JS right now. (We have inert, but it's much harder to selectively apply the inert attribute to everything else on the page than it is to tell the page, "Only this element shouldn't be inert.) So all that's really missing here is the ability to make everything else on the page inert.

An added ability to arbitrarily put something in the Top Layer could be great, but it's also probably sufficient to carefully write out the HTML and CSS so that the <form> successfully appears above everything else.

If the team is open to considering something that's like the inert attribute but that makes the rest of the page inert instead, maybe that could be useful.


Some Counter Thoughts

**That said**, after racking my brain on my project's version of @mrksbnch's use case, I'm not sure if a `defaultopen` popover is really what we're looking for. What's important to consider is that when `/users/:id/edit` (or some similar url) is visited, the user will be scrolled back to the top of the page (if I understand correctly). Let's say an administrator is on a user list page, scrolls `400dvh` down the screen, and clicks a user. Now they're brought back to the top of the screen, but they see a modal with a form for a user that's `400dvh` downwards. When they submit their edits, they're likely redirected from `/users/:id/edit` back to `/users`, but they still may not be returned to the scroll position for the user whom they edited. This actually seems like a more confusing user experience. I think it's more intuitive for users to be redirected to a form-only user-edit page that redirects them back to the users list. And the reason I think this is more intuitive is that a person without JS will probably still expect to maintain their scroll position if a modal form appears on top of the user list. Having expectations shattered is a worse UX. Basically, I think the user experience with scroll positioning is the killer here. And it would probably be better to have a form-only page for non-JS users and a modal for JS users (so that people can maintain their scroll position). Of course, there's also the option of forcing all users to go to the form-only page. Maybe the story would be different if we had a way to tell browsers to scroll to a particular element without JS. :thinking:
github-actions[bot] commented 1 month ago

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.

kizu commented 1 month ago

In my practice, I had countless examples where some popover or dialog had to be open by default for one reason or another.

Michael-Paragonn commented 1 month ago

tl;dr: When you need to have a "Page is loading" overlay that must be in the top layer, for Reasons™.

Details:

I'm currently dealing with a client site that could really use popovers that load in their opened state by default. Here's the situation:

When the user navigates to another page, the client wants to have a full-page overlay slide up from the bottom to cover the entire page, and then slide up out of frame when the new page loads in; SPA-like page transitions, but without the SPA.

I had implemented this as a regular <figure> element (since there's a little logo centered in the overlay) with @keyframe animations to control "sliding-up-in" and "sliding-up-out". Worked like a charm; when the user clicked a link, JS would preventDefault(), then add a class to the <figure> that would apply the "sliding-up-in" animation, and finally after a short setTimeout() to allow the sliding-up animation to finish, would set window.location.href to the href of the clicked link. Then when the new page loaded, the <figure> overlay would start out in the shown state, but with the "slide-up-out" animation to reveal the new page's contents.

Enter the <dialog>.

The site now needs to be able to link to other pages from inside a <dialog> element. However, since <dialog> is now located in #top-layer, the <figure> overlay slides-up-in behind the <dialog> instead of in front of it. 🤦‍♂️

So I converted the <figure> into a popover. Works great! Now it slides-up-in in front of the <dialog>. BUT... the new page doesn't show the popover overlay on page-load... because popover. 🤷‍♂️

Michael-Paragonn commented 1 month ago

Another example I just encountered: I'm dealing with a Craft CMS plugin (Sprig, which is based on HTMX), which, when an action is performed, can add a class to an element, but not run arbitrary JS. So, onClick="el.classList.add('SOMEthing')", not onClick="el.doSOMEthing()".

It'd be really useful to be able to activate a popover by adding/removing a classname.

scottaohara commented 1 month ago

i'm not sure i really understand why this can't just be done using the popover API, and why it needs to be declaratively open by default?

for your initial use case, of a loading indicator that overlays the page - that sounds like something where if you're not already using a modal dialog for that - you'd need to at least be implementing that sort of overlay with some JS to handle making sure the content under the overlay is inert (you mentioned you were using JS for preventing default with clicking - but i'd assume a keyboard/screen reader user could still access content beneath the overlay since you didn't mention using inert/or a modal dialog to implement this).

for your follow up post about being able to activate a popover by adding/removing a class name - that is again something contingent on using JS... so if you're going to do that, then just use the API to show/hide popovers - if that's actually what needs to be done per all the above about making sure any overlay you have is actually meeting all accessibility requirements.

Michael-Paragonn commented 1 week ago

That's a good point about making the overlay a modal dialog; I hadn't considered that since I've always thought that <dialog>s are meant to be interactive in some way, semantically-speaking.

But perhaps that's just the point—why should a <dialog> have an HTML attribute to control its state, and a popover not? Is it because any element can be designated as a popover, whereas a <dialog> is its own specific element?

scottaohara commented 1 week ago

a dialog can't (presently) be open by default as modal.

if / when it could be marked as open and modal by default, then it would do all the necessary things to block users from reaching the underlying web page. A popover cannot do this because a popover cannot be modal, because doing so would make it a modal dialog then, and we already have that element in HTML.

...semantically-speaking

I'd respectfully respond to this saying that your read on the dialog element semantics is a bit strict. By comparison, using the figure element as a popover to render a loading icon is a very loose interpretation of the figure element's intended semantics. A figure's most prominent / intended usage being to present content, often with a caption, as cited/in support of content within a larger section/article of content. Using it to contain an image to render as a popover is not really matching its intended usage, and would likely seem an awkward container element role for someone encountering this while using a screen reader. A dialog, on the other hand, particularly a modal, is far more suited to the task of presenting a message (loading indicator) / making the underlying page inert while the page finishes loading.

I'm not meaning to get into a fight over "semantics", so i say this in hopes of clarifying. Rather, I say all that to provide rational for why i'm questioning the use case, as it sounds like what you want is a modal dialog, but are trying to achieve this with popover so as to not use JS... even though JS is being used to handle the other aspects of this use case. I hope that helps further clarify my thoughts on the matter.