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

[popup] Add further clarity that popup is not (presently?) for modal dialogs #581

Closed
scottaohara opened this issue Aug 16, 2022 · 18 comments · Fixed by #593
Closed

[popup] Add further clarity that popup is not (presently?) for modal dialogs #581

scottaohara opened this issue Aug 16, 2022 · 18 comments · Fixed by #593
Labels
popover The Popover API

Comments

@scottaohara
Copy link
Collaborator

Per discussion on the open ui discord initiated by @tbondwilkinson, there is some value in further identifying the differences between a "popup" and a "modal dialog" and why the disallowed elements section calls them out as not supporting popup.

Potentially adding to the goals section (or non-goals), examples, or even expanding the initial background section to help further clarify the differences between UI elements that "float" on screen and how not all floating content should be considered a "popup".

@tbondwilkinson please do add any of your thoughts here, as I'm sure my brief intro to the topic is not doing justice to your concerns.

@tbondwilkinson
Copy link

tbondwilkinson commented Aug 16, 2022

I think as a component author coming to see whether the Popup API is a good fit for specific components, having a good sense of where the Popup API is or is not a fit would be helpful.

Things like:

  1. Content is usually ephemeral, and does not stand alone from the content of the page
  2. Popups are displayed one a time, and others should dismiss when one is shown.
  3. Popups leave the rest of the page interactable
  4. Popups may anchor to specific elements or they may float above the page

Which would highlight the expected behavior.

@bkardell
Copy link
Collaborator

Is #1 inherent? I've been talking a bit to some other folks trying to understand the boundaries of popup use cases and whether or not popups were inherently popups, or they could be sometimes afforded that particular nature. For example, what about 'hamburger menus' - they are often just content, unless they are acting as a kind of popup because we've hidden the content by default. Or, in a form I might have some helpful text about what belongs in the field ("Your password must contain...") which we'd like to 'hint' one at a time on most devices, but... maybe if I had a reason to print that form I'd like to just display it inline. If either of those is potentially viable use cases for popup it seems to make #1 a complicated criteria to me.

@tbondwilkinson
Copy link

I think @mfreed7 mentioned that requirement (or was it more of a suggestion?) to me. Personally, I think it's reasonable for popup to serve use cases that are beyond just supporting content. I would love to hear other's thoughts.

@scottaohara
Copy link
Collaborator Author

scottaohara commented Aug 17, 2022

re:

they are often just content, unless they are acting as a kind of popup because we've hidden the content by default.

does it overlay other content of the page and it would show/hide based on behaviors that are not commonly associated with the default semantics of the elements in question? e.g., a list of navigational links? Then that's a popup.

if the hamburger navigation is shown/hidden in the normal flow of the document - e.g., does not render atop other content, then it is not a popup. similar to the form error messages (though, i would submit if they are not inline/persistent, then these would likely be problematic).

re: the trigger that started this conversation - a modal dialog with light dismiss behavior is not a popup, as its modality and thus the inertness it applies to the underlying document make this distinct of popups. A popup generally should not be modal - particularly on desktop / larger viewports.

However, a modeless dialog could be a popup indicating that this version of a dialog has light-dismiss behavior that is otherwise unexpected of a modeless dialog (as with other elements that can be popup but would not generally be expected to 'hide' upon focus leaving said elements).

Interested to know if after all this time people have different understandings of popup. If so, we need to align on this - particularly since potential spec text is being written for the attribute.

Personally, I think it's reasonable for popup to serve use cases that are beyond just supporting content

i'd agree, but there's nuance there.

Take Brian's hamburger navigation as an example. The navigation container would be persistent in this case - it doesn't represent "supporting" content - but it (the nav element) is also NOT the popup. The contents of the navigation could be provided popup behavior (so long as it actually did overlay atop other content).

<nav>
  <button type=button popuptoggletarget=f>Menu</button>
  <ul id=f> <!-- all my links n' such --> </ul>
</nav>

The reason being that you always want this navigation exposed. It is an important landmark for people using assistive technologies to quickly find the navigation content. The button within represents the trigger to toggle the contents of the navigation. the list contains the items - and is itself the popup. OR, a <div> could be used to wrap the list for styling purposes.

I guess, stepping back a bit, it depends on how you define "supporting content". Yes the list of links is the star content of the navigation element, but the navigation element itself is the main player here. Without it - this is just a list containing links. Why's that important? Oh, because it represents the content of the navigation.

@tbondwilkinson
Copy link

I see, so in your thinking the navigation hamburger is part of the proper "content" of the page, in that it's always visible, and the expanded display of the navigation hamburger menu's contents could reasonably be considered a popup, if those contents were rendered above content when in the shown state.

I think that clarifies things for me

@mfreed7 mfreed7 added the popover The Popover API label Aug 19, 2022
@mfreed7
Copy link
Collaborator

mfreed7 commented Aug 19, 2022

First, thanks for this discussion - it'll be very important to have good developer guidance on when to think about <dialog> and when to think about popup. Generally, I think the thread has reached a conclusion I agree with (the main distinction is that popup is non-modal), so I won't add too much.

However, a modeless dialog could be a popup indicating that this version of a dialog has light-dismiss behavior that is otherwise unexpected of a modeless dialog (as with other elements that can be popup but would not generally be expected to 'hide' upon focus leaving said elements).

Interested to know if after all this time people have different understandings of popup. If so, we need to align on this - particularly since potential spec text is being written for the attribute.

This is an interesting question to me: for the developer guidance I mention above, what distinguishes a non-modal <dialog> from a <div popup=manual>? On their face, they're similar, and likely could serve similar purposes. Here are the differences I see:

  1. (Most important) <div popup=manual> is in the top layer. I'm unclear how someone might realistically use a modeless <dialog> without having to do gyrations to make sure it's visible on top of content.
  2. The pop-up API comes with some "nice to have's" like a "show" event, compatibility with the invoking attributes (e.g. popuptoggletarget), and the provisions for easily animating the show and hide transitions.
  3. Semantics. The <dialog> is always role=dialog (modulo ARIA), while popup can be applied to the most-semantically-relevant HTML element.

The last point is interesting: perhaps the most common application is role=dialog. In that case, if the additional features above push developers towards popup=manual, then maybe they should be using <dialog popup=manual>. I.e. a <dialog> element (to get role=dialog) with Pop-up API behaviors.

@tbondwilkinson
Copy link

<dialog popup="manual"> isn't a use case that works today though, is it? Would it throw an error in the JS API?

@mfreed7
Copy link
Collaborator

mfreed7 commented Aug 19, 2022

<dialog popup="manual"> isn't a use case that works today though, is it? Would it throw an error in the JS API?

Right, today it would throw. But it seems like perhaps it would be better if it didn’t? Maybe it should only throw if the dialog is already modal?

@tbondwilkinson
Copy link

It does feel like that's pretty subtle though for people to understand, and I wonder how it compares to something like <popup="dialog"> to get the ARIA role instead, because if you're JUST using <dialog> for the role, the fact that it comes with JS APIs that could also potentially throw errors if you use it wrong feels wrong.

Maybe we should open a distinct issue to think more about support for other non-modal UI components that perhaps already have some amount of browser standardization, like <dialog>

@mfreed7
Copy link
Collaborator

mfreed7 commented Aug 19, 2022

It does feel like that's pretty subtle though for people to understand, and I wonder how it compares to something like <popup="dialog"> to get the ARIA role instead, because if you're JUST using <dialog> for the role, the fact that it comes with JS APIs that could also potentially throw errors if you use it wrong feels wrong.

Maybe we should open a distinct issue to think more about support for other non-modal UI components that perhaps already have some amount of browser standardization, like <dialog>

Please see #495, particularly this comment, which we resolved to accept, and which I'd really like to avoid re-opening. Essentially, the semantics (and therefore the role) come from the element, not the popup attribute. And the plan is that once the pop-up API spec lands, we can more easily add new elements like <tooltip> that utilize the spec machinery provided by pop-up, but provide more specific semantics for a given use case.

Given the above, picking an element should primarily be about matching the semantics of the content. I.e. if you're building a "dialog", then you should pick the <dialog> element. Or at the very least use <div popup role=dialog>.

For me at least, <dialog popup> feels ok. E.g.

<!-- This is a "dialog", so it should use a <dialog> element: -->
<dialog popup>I'm a "light dismiss" dialog</dialog>

<script>
const dialog = document.querySelector('dialog[popup]');
dialog.showModal(); // Please show me as a modal dialog!
dialog.close(); // Calling showPopUp while already modal *should* throw.
dialog.showPopUp(); // Please show me as a light-dismissible pop-up!
</script>

It feels rather self-documenting, to me at least. Can you clarify what about the above feels wrong? Perhaps we can mitigate the wrongness somehow.

@tbondwilkinson
Copy link

tbondwilkinson commented Aug 19, 2022

I think what I'm feeling meh about is mostly the design of <dialog>. I love that you all have made a distinction between semantics and behavior, that actually feels really correct.

I guess in an ideal world what I'm looking for is:

<dialog popup>I'm a "light dismiss dialog"</dialog>

<script>
const dialog = document.querySelector('dialog[popup]');
dialog.showModal(); // throws an error, because dialog is behaving as a popup, not a modal.
dialog.showPopUp(); // this is correct, because the dialog has been marked as a popup.
</script>

And to make that feasible, dialog should be modal by default, or you could even introduce a new attribute modal or some other name that categorizes things that behave as modals, distinct from popups.

<dialog modal>I'm a "modal" dialog</dialog>

<script>
const dialog = document.querySelector('dialog[modal]');
dialog.showPopUp(); // this should throw an error, the dialog is not a popup.
</script>

Basically I think what I'm saying is that currently <dialog> comes with BOTH semantics AND behavior, and I think it would be good to move what is today behavior to an attribute, and leave the semantics to <dialog>.

I guess there's probably some debate to be had as to whether you should allow overlapping behavior (and choose to be behave as either modal or popup) but my preference is that it's confusing and you should instead just pick one or the other. If you have multiple attributes like both popup and modal, you could just pick the first one that appears structurally in the HTML.

@scottaohara
Copy link
Collaborator Author

And to make that feasible, dialog should be modal by default,

this would have the potential to be dangerous. A dialog being non-modal by default is more forgiving of author error and more forgiving for users who may change the stylesheet of a site to make it more usable for them. An accidental display: -something-other-than-none- set to a dialog that is modal by default means that the page becomes unusable to someone using assistive technology. The fact that a dialog is only modal via the showModal() method is a good thing.

@tbondwilkinson
Copy link

Non-modal is a fine default too.

My main issue here is not really suitable defaults, which clearly you have a better sense of than me. My main issue is that <dialog> and popup feel like they diverge.

  1. <dialog> confers behavior and semantics. Popup only confers behavior. Is it possible to move dialog behavior to an attribute (modal, nonmodal, etc.) to make that cleaner?
  2. <dialog> behavior and semantics are deferred until you call one of the applicable methods. Should you instead declare up front whether your dialog is modal or not?

@mfreed7
Copy link
Collaborator

mfreed7 commented Aug 22, 2022

I see your points, but I think the <dialog> ship might have sailed. It does sound like perhaps we're coming to the conclusion that modeless <dialog> might not have much of a use case, at least as compared to <div popup=manual>. And if that becomes the explicit guidance, then <dialog> is really left for modal dialogs. It's not explicitly declared in HTML (i.e. there's no attribute called dialog-is-modal), but in spirit, it solves the problem you're raising: all <dialog>s are modal. I suppose that's not a very satisfying answer.

@tbondwilkinson
Copy link

I'm fine if the <dialog> ship has sailed. FWIW it's usage has been decreasing.

I guess to close this up a bit:

  1. popup is modeless.
  2. Because popup is modeless, <dialog popup> I think should throw on the modal methods, and be treated instead as a modeless dialog in all cases. I think current behavior of being either modal or modeless depending on which JS API is a foot gun, because it means an element attribute with popup can be shown in a modal way if it's attached to a <dialog>. Should I open an issue for this?
  3. Perhaps we can circle around to a new API that would provide support for modal UI, that could supersede <dialog> and be more similar in spirit to the Popup API.

To get back to the main thrust of this issue, is someone going to update the explainer to better reflect the design principles of popups, or is there more discussion to be had about what those principles are?

@mfreed7
Copy link
Collaborator

mfreed7 commented Aug 22, 2022

  1. popup is modeless.

Agree.

  1. Because popup is modeless, <dialog popup> I think should throw on the modal methods, and be treated instead as a modeless dialog in all cases. I think current behavior of being either modal or modeless depending on which JS API is a foot gun, because it means an element attribute with popup can be shown in a modal way if it's attached to a <dialog>. Should I open an issue for this?

I think this makes a lot of sense. It seems like calling .showModal() on a <dialog popup> is a mistake. I think this is exactly the question being asked here: #520. I'll add a comment there, pointing back to this discussion. A nested bit of your proposal is that we need to explicitly allow dialog.showPopUp(), which we haven't really resolved yet.

  1. Perhaps we can circle around to a new API that would provide support for modal UI, that could supersede <dialog> and be more similar in spirit to the Popup API.

I like this approach. Perhaps a new <modelessdialog> element? <nonmodaldialog>? <ephemeraldialogthatwillgoawayifyouclickoutside>? Bikeshedding is obviously required.

To get back to the main thrust of this issue, is someone going to update the explainer to better reflect the design principles of popups, or is there more discussion to be had about what those principles are?

We can do that. I think part of that guidance will actually need to be part of the spec PR, but that remains to be seen. I agree that this should be written down, because it's a popular question.

@mfreed7
Copy link
Collaborator

mfreed7 commented Aug 22, 2022

So the leftover action item in this issue is simply to update the documentation and/or spec. Is that right?

mfreed7 added a commit to mfreed7/open-ui that referenced this issue Aug 23, 2022
The largest change is the result of [this discussion](openui#581) about the differences between dialog and popup=manual. There's a new section attempting to describe those differences. This PR also includes recent changes to the `show` event, and an update on the interaction between top layer element types.

This PR also removes an obsolete section of the `<selectmenu>`
page that talks about replaceable shadow DOM.
@mfreed7
Copy link
Collaborator

mfreed7 commented Aug 23, 2022

PR to update the explainer is here: #593

Comments/reviews appreciated.

mfreed7 added a commit to mfreed7/open-ui that referenced this issue Aug 30, 2022
The largest change is the result of [this discussion](openui#581) about the differences between dialog and popup=manual. There's a new section attempting to describe those differences. This PR also includes recent changes to the `show` event, and an update on the interaction between top layer element types.

This PR also removes an obsolete section of the `<selectmenu>`
page that talks about replaceable shadow DOM.
gregwhitworth pushed a commit that referenced this issue Sep 8, 2022
* Add recent OpenUI discussion results

The largest change is the result of [this discussion](#581) about the differences between dialog and popup=manual. There's a new section attempting to describe those differences. This PR also includes recent changes to the `show` event, and an update on the interaction between top layer element types.

This PR also removes an obsolete section of the `<selectmenu>`
page that talks about replaceable shadow DOM.

* Address comment

* Address ::backdrop comment

* Address comments

Co-authored-by: Mason Freed <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
popover The Popover API
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants