diff --git a/research/src/pages/popup/popup.proposal.mdx b/research/src/pages/popup/popup.proposal-v1.mdx similarity index 98% rename from research/src/pages/popup/popup.proposal.mdx rename to research/src/pages/popup/popup.proposal-v1.mdx index 3c5a59404..e9e6fbd71 100644 --- a/research/src/pages/popup/popup.proposal.mdx +++ b/research/src/pages/popup/popup.proposal-v1.mdx @@ -1,7 +1,7 @@ --- menu: Proposals -name: Popup (Editor's Draft) -path: /components/popup +name: Popup Element Spec Proposal (Abandoned) +path: /components/popup.proposal-v1 pathToResearch: /components/popup.research --- @@ -12,6 +12,10 @@ import '../../styles/spec.css' - Mason Freed (Google) - Melanie Richards (Microsoft) +# Note: This is an outdated proposal! + +Please see the updated version [here](/components/popup.research.explainer). + ## HTML Incubation Text: Popup _Target venue: [HTML Living Standard](https://html.spec.whatwg.org/multipage/)_ diff --git a/research/src/pages/popup/popup.proposal.alternatives.mdx b/research/src/pages/popup/popup.proposal.alternatives.mdx new file mode 100644 index 000000000..8bc5eabd3 --- /dev/null +++ b/research/src/pages/popup/popup.proposal.alternatives.mdx @@ -0,0 +1,532 @@ +--- +name: Popup API Alternatives +path: /components/popup.proposal.alternatives +showInMenu: false +--- + +- [@mfreed7](https://github.com/mfreed7) +- March 16, 2022 + + + +## Table of Contents + + - [Alternative: An HTML Content Attribute (OLD version)](#alternative-an-html-content-attribute-old-version) + - [Alternative: Dedicated `` Element](#alternative-dedicated-popup-element) + - [Alternative: CSS Property](#alternative-css-property) + - [Alternative: JavaScript API](#alternative-javascript-api) + + + +# Background + +This is a companion document to the main [Popup proposal](/components/popup.research.explainer), and it walks through various alternative approaches to the same problem, listing their pros and cons. Each of the approaches detailed in this document **was [rejected](https://github.com/openui/open-ui/issues/455#issuecomment-1050172067) in favor of the [HTML content attribute](/components/popup.research.explainer) approach**. + + +## Alternative: An HTML Content Attribute (OLD version) + +This is an older version of an HTML content attribute proposal. The primary difference is that this version leaves all of the details of one-at-a-time and light dismiss behavior to the developer, to implement in Javascript. There seem to be many footguns inherent in this approach, as compared to the more [prescriptive UI classes](#classes-of-ui---dismiss-behavior-and-interactions) presented above. As such, this version was abandoned for the [current proposal](#html-content-attribute). + +### API Shape + +#### Top Layer Presentation + +This can be implemented with a new global HTML content attribute:: + + +``` + + + + +``` + + + +* This allows any element to be added to the top-layer. +* Admittance to the top-layer is not guaranteed or permanent - the UA can both deny an element access to the top-layer and can remove an element if needed. For example, when a modal dialog is shown or an element is made [fullscreen](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullScreen), or a user preference desires it - those changes might “kick out” other elements residing in the top-layer. +* Some element types should likely not be allowed into the top-layer **via the API described in this document**. E.g. ``? Or any element that is currently fullscreen? +* The toplayer attribute can be added or removed by either the developer or the UA, and in both cases, the behavior will be the same. Adding `toplayer` promotes the element to the top layer, and removing the attribute removes the element from the top layer. In the case that the UA “denies” access to the top layer, it will immediately remove the attribute. + + +#### The :top-layer Pseudo Class + +For at least the `` use case, developers need to be able to style things differently when the `` is being shown. To enable this, we also need to add a CSS `:top-layer` pseudo-class: + + +``` + popup { + opacity: 0; + transform: translateY(50px); + transition: all 1s; + } + popup:top-layer { + opacity: 1; + transform: translateY(0); + } + +``` + + + +* This pseudo class matches when an element is in the top-layer for any reason. That includes fullscreen or modal dialog elements. +* This pseudo does not simply match if the element has `computedStyle.position` equal to top-layer (see below), but only triggers if the element is actually in the top layer. + + +#### Events + +There is a [general desire](https://github.com/openui/open-ui/issues/342) to receive events indicating that an element has entered or left the top layer via this API. These events can be used, for example, to populate content for a popup just in time before it is shown, or update server data when it closes. Additionally (see the section below), these events could be used to allow the application to prevent or force closing a popup in some circumstances. + +It would seem most natural and powerful to define two events: + +* `entertoplayer`: fired on the element just after it is promoted to the top layer. +* `exittoplayer`: fired on the element just after it is removed from the top layer. + +Both events would use a new TopLayerEvent interface, inheriting from [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event). These events would be typically cancellable, to prevent addition or removal when desired. For some types of transition, e.g. the UA forcibly removing an element from the top layer, the events would simply **not** be cancellable. + +It would also seem natural that these events would be fired for `` elements and fullscreen elements, as they transition into and out of the top layer. + + +#### Dismiss Behavior + +For elements that are displayed on the top layer via this API, there are a number of “triggers” that should cause the element to be removed from the top-layer. These fall into two main categories: + + + +* **Light Dismiss**. User action such as clicking outside the element, hitting Escape, or causing keyboard focus to leave the element. This is typically called “light dismiss”. +* **One at a Time.** Another element being added to the top-layer causes others to be removed. This is typically used for “one at a time” type elements: when one popup opens, other non-ancestor popups should be closed, so that only one is onscreen at a time. + +Both categories can be implemented via the events presented above, using this as the TopLayerEvent interface, which is used for all toplayer events: + + +``` +interface TopLayerEvent : Event { + readonly attribute DOMString reason; +}; +``` + + +To use this interface to control **light dismiss**, the `reason` attribute will contain the “reason” the element is being removed from the top layer: + + + +* “blur” - focus was removed from the element. +* “click-outside” - a click event was received that did not fall within the element's bounding box. +* “close-signal” - a [close signal](https://wicg.github.io/close-watcher/#close-signal) was received, e.g. the ESC key. Possibly not cancellable in this case. +* “scroll” - the window was scrolled. +* “UA” - the UA is removing this element from the top layer, typically to display another element such as a fullscreen. + +If the `exittoplayer` event is cancelable, then this event can be canceled when the element does not want to be dismissed via the provided `reason`. For example: + + +``` +tooltip.addEventListener('exittoplayer',(e) => { + if (["blur","scroll"].includes(e.reason)) + e.preventDefault(); // Blur and scroll shouldn't dismiss tooltips +}); +``` + + +To use this interface to control **one at a time** behavior, a simple querySelectorAll loop can be used within the `entertoplayer' event handler: + + +``` +tooltip.addEventListener('entertoplayer',() => { + for (const other of document.querySelectorAll('[toplayer]')) { + other.removeAttribute('toplayer'); + } +}); +``` + + +In all cases above, the UA would need to fire the event handler synchronously, so that these event handlers could be used to change rendering without any flashes of differently-styled content. + +If a “less Javascripty” interface was desired to expose this behavior, another way to achieve this would be to add a new CSS property, whose value is a selector: + + +``` +.popup { + close-other: .tooltip, .popup, my-tooltip, dialog[open]; +} +``` + +In this case, when an element matching .popup is promoted to the top layer, anything matching the closeother property's selector value will be removed from the top layer. This would behave identically to the Javascript entertoplayer listener coded above. + +In both of the above examples, any elements removed from the top layer this way will themselves receive a `exittoplayer` event, meaning they can cancel this removal. + + +#### Focus Management + +Elements that “go” into the top layer sometimes need to move the focus to that element, and sometimes don't. For example, a modal `` gets automatically focused because a dialog is something that requires immediate focus and attention. On the other hand, a `` doesn't receive focus at all (and is typically not expected to contain focusable elements). Similarly, a `` should not receive focus (even if focusable) because it is meant for out-of-band communication of state, and should not interrupt a user's current action. Additionally, if the top layer element **should** receive immediate focus, there is a question about **which** part of the element gets that initial focus. For example, the element itself could receive focus, or one of its focusable descendants could receive focus first. For these reasons, there need to be mechanisms available for elements to control focus in the appropriate ways. The `` element proposal provided two ways to modify focus behavior: the `delegatesfocus` and `autofocus` attributes. The `autofocus` attribute is [already a global attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus), so it'd just need to be updated to clarify that the autofocus behavior happens for top layer elements right when they're added to the top layer. The other attribute provided by the `` proposal, `delegatesfocus`, either might not be necessary, or might need to be added as a global attribute: + + + +* Applicable to any element. +* When an element with `delegatesfocus` is focused, the first focusable descendent of that element is focused instead. This is regardless of the element's top-layer status. (This can be added using the [focus delegate spec](https://html.spec.whatwg.org/#focus-delegate).) + +The use cases for these attributes need to be better enumerated. + + +#### Declarative Triggering (The `popup` Attribute) + +One feature provided by the `` proposal was the ability to use the `popup` content attribute on a triggering element (e.g. a button) to enable that element to show a `` when activated, without requiring Javascript. + +To implement this via the HTML toplayer attribute, when the element with the popup attribute is activated by the user, the target element will simply have the `toplayer` attribute added to it by the UA, which will trigger it being placed into the top layer. In order for this to make a previously-invisible popup menu “show up”, CSS would need to be used: + + +``` + my-popup { + display: none; + } + popup:top-layer { + display: block; + } +``` + + +There could also be other such declarative attributes, e.g. `tooltip`, which trigger the popup after a hover delay, in exactly the same way as the `popup` attribute. + +When the `popup` attribute is applied to an activating element, the `ariaHasPopup` property should be set appropriately by the UA. + + +#### Anchoring (The `anchor` Attribute) + +Another feature provided by the `` proposal was the `anchor` content attribute, which provided two functionalities: + + + +1. Establish the provided anchor element as an “ancestor” of this `` for the purposes of light-dismiss behavior. In other words, when a `` element was shown, all other `` would be closed **except** for the ancestor chain of anchor popups. +2. The referenced anchor element could be used by the [Anchor Positioning feature](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/CSSAnchoredPositioning/explainer.md). + +Of these, #2 can still be achieved with a general-purpose `anchor` content attribute. It is possible that behavior #1 can also be achieved for general purpose top-layer elements. But this may be a bit odd. + + +#### Display Ordering and the `initiallyopen` Attribute + +The `` proposal had an `initiallyopen` attribute which could be used to show the `` upon page load. Within the HTML attribute solution, this is now unnecessary. Any elements that contain the `toplayer` attribute when the document is loaded will be shown in the top layer by default. + +As with the original proposal, if multiple such elements are found on a page, and they make use of the ``other-top-layer-element`` light dismiss trigger, only the last such element on the page will remain open when the page is fully loaded. + + +#### Accessibility / Semantics + +Since the `toplayer` content attribute can be applied to any element, and only impacts the element's presentation (top layer vs not top layer), this should not have **any semantic or accessibility impact**. I.e. the element with the `toplayer` attribute will keep its existing semantics and AOM representation. + + +### Pros and Cons + + +#### Pros + + + +* Solves the [Accessibility/Semantics problem](#alternative-dedicated-popup-element). +* Solves the [“removal from top layer” problem](#dismiss-behavior-2) inherent in the CSS solution. When the element is removed from the top layer, the UA can also remove the content attribute. +* Solves the [issue with the popup declarative attribute](#declarative-triggering-the-popup-attribute-1) in the CSS solution. +* Solves the [potential display ordering issues](#display-ordering-and-the-initiallyopen-attribute-1) raised by the CSS solution. +* Works on any element. +* Still good DX: it should be easy for developers to understand the meaning of an attribute on an element that is in the top layer. + +#### Cons + +* In some use cases (as [articulated here](https://github.com/openui/open-ui/issues/417#issuecomment-996890656)), the use of a content attribute might cause some DX issues. For example, in the `` application, we might want to make in-page vs. popup presentation an option. To achieve that via a `toplayer` HTML attribute, there might need to be some mirroring of attributes from the light-dom `` element to internal shadow dom container elements, which makes the shadow dom replacement feature of `` a bit more complicated to both use and implement. + + +## Alternative: Dedicated `` Element + +The initial [proposal](https://open-ui.org/components/popup.research.explainer) describes, in detail, the dedicated `` element approach. However, in several discussions ([1](https://github.com/w3ctag/design-reviews/issues/680#issuecomment-943472331), [2](https://github.com/openui/open-ui/issues/410), [3](https://github.com/openui/open-ui/issues/417#issuecomment-985541825), and more) the OpenUI community brought up several accessibility concerns: + +* **Semantic definition of ``.** The first question [raised](https://github.com/w3ctag/design-reviews/issues/680#issuecomment-941533235) about `` was “what is the semantic definition of a ``?”. There are several possibilities, and the answer depends on the use case. One potential answer is that a `` is quite similar to (and so could re-use the semantic definition of) a non-modal dialog. But for some use cases, e.g. listboxes and action menus, a non-modal dialog is not the correct semantic, nor would the accessibility mappings associated with a non-modal dialog be expected or desired for these use cases. (See [this spreadsheet](https://docs.google.com/spreadsheets/d/1v4RXKrvp-txG477GNH42gFSzX_HkRYJk-eap6OgAorU/edit#gid=0) for a list of possible use cases and their potential semantics/roles). Therefore, to have a “general purpose” `` element, the documentation would need to clearly prohibit these “different” use cases, and instead point to other elements (many of which don't yet exist, and might never exist). +* **Default ARIA role**. Quite related to the above point, but separate and nuanced, is the question of the default ARIA role for the new `` element. One suggestion for the generic use case is “role=dialog” (non-modal), another is “role=group” (which is fairly generic), and a third is no role at all (akin to a `
`). There are differences of opinion ([1](https://github.com/openui/open-ui/issues/417#issuecomment-991383119),[2](https://github.com/openui/open-ui/issues/417#issuecomment-996179842),[3](https://github.com/openui/open-ui/issues/417#issuecomment-996247945)) about which of these make the most sense, and the accessibility community is quite concerned that we might do harm to the AT user community. There does not seem to be one default role that will “work” in the various “generic” use cases for the `` element approach. They do seem to strongly agree that there are some use cases (e.g. listbox) for which we **must not** use a generic `` element. Generally, picking a single role for a “generic” `` violates the goal of [“Accessible by default”](#goals). + +The above accessibility/semantic issues were discussed numerous times, both in the issues linked above, and at live OpenUI meetings ([1](https://github.com/openui/open-ui/issues/410#issuecomment-948874366),[2](https://github.com/openui/open-ui/issues/410#issuecomment-948975506),[3](https://github.com/openui/open-ui/issues/410#issuecomment-961390034),[4](https://github.com/openui/open-ui/issues/410#issuecomment-973271554),[5](https://github.com/openui/open-ui/issues/417#issuecomment-984957942),[6](https://github.com/openui/open-ui/issues/417#issuecomment-996213305)). We were never able to make progress towards a resolution to go forward with a generic `` element, due to these specific concerns. + +The **recommendation from the AX community is to separate the behavior from the element**. By not tying the behavior to a specific `` element with defined semantics and ARIA mappings, and instead using another mechanism to invoke the presentation/behavior, we will be able to sidestep all of the above problems. + +In addition to the AX concerns discussed above, this approach (a dedicated `` element) generally violates the [separation of content and presentation](https://en.wikipedia.org/wiki/Separation_of_content_and_presentation). The `` element comes with inseparable presentational qualities such as being presented on top of all other content. Perhaps this is really the fundamental reason for the semantic and accessibility issues we're encountering? + +Finally, the current `` element proposal does not support the Hint or Async use cases, at least due to their requirements to not dismiss other top layer elements when shown. + + +### Overall Pros and Cons + + +#### Pros + +* Good DX: An HTML element is easy to understand and use. +* It is relatively easy to write down exactly how the `` element should interact with the other top-layer elements, because it is a single element. + +#### Cons + +* Unclear that there is a solution to the [Accessibility/Semantics problem](#alternative-dedicated-popup-element). +* Ties the top-layer presentation to the HTML structure. I.e. to get something to be top-layer, it must be “wrapped” in a `` element. +* Does not support more general use cases, such as Hint and Async. Those would require other new elements to be proposed. + + +## Alternative: CSS Property + +This approach, on its face, seems very simple and elegant. However, there are two very significant downsides to this approach: + * A “dual class” top layer will need to be created, with `` and fullscreen always above “developer” top layer elements. That **precludes using a popup** on top of a dialog/fullscreen. + * In this approach, light dismiss and one-at-a-time behavior cannot be built into a CSS property, and **must be implemented in JavaScript**. + +For these two reasons, this approach was abandoned in favor of the [current HTML attribute proposal](#html-content-attribute). + + +### API Shape + + +#### Top Layer Presentation + +This can be implemented with a new value for the CSS position property: + + +``` + popup { + position: top-layer; + } + +``` + + + +* This allows any element to be added to the top-layer. +* In order to use CSS to control top layer access, there would no longer be a way to deny or remove an element from the top layer, for example when a modal dialog or fullscreen element needs to be shown. Therefore, this “developer top layer” would need to be located **underneath** the “UA top layer”, so that there was never any need to remove elements from the developer top layer. +* Some element types should likely not be allowed into the developer top-layer, such as already-modal ``s and fullscreen elements. +* Importantly, in such a “two class” top layer world, this new CSS property could never be used to display top layer UI on top of UA top layer elements such as modal dialogs and fullscreen elements. This seems like a rather large downside. + + +#### The :top-layer Pseudo Class + +If access to the top layer was controlled via CSS, there could not be a CSS selector to select items in the top layer. That would cause circularity problems, such as: + + +``` +div { top-layer: yes } +div:top-layer { top-layer: no } +``` + + +However, if control of the top layer was provided via CSS, the pseudo class would probably be superfluous. Any desired properties could just be placed into the existing selectors that trigger `top-layer:yes/no`. + + +#### Dismiss Behavior + +As mentioned above, a CSS-based approach precludes any way for the UA to “force” elements out of the top layer. Therefore, to implement the light dismiss and one-at-a-time functionality discussed in [this section](#dismiss-behavior-1), a similar event-based approach would need to be used. In this case, there would need to be three events: + + + +* `entertoplayer`: fired on the element just after it is promoted to the top layer. +* `exittoplayer`: fired on the element just after it is removed from the top layer. +* `lightdismisstrigger`: fired on the element when there was a possible light dismiss trigger, such as a user clicking outside the element, or hitting Esc. + +To implement light dismiss, the `lightdismisstrigger` event would include a `reason` field that could be used to take action: + + +``` +interface LightDismissEvent : Event { + readonly attribute DOMString reason; +}; +``` + + +This event and reason field would be nearly identical to the one [described here](#dismiss-behavior-1). It could be used to modify the top layer status, e.g.: + + +``` +tooltip.addEventListener('lightdismisstrigger',(e) => { + if (["click-outside","close-signal"].includes(e.reason)) + e.target.classList.remove('toplayer'); // Esc and click should dismiss +}); +``` + + +To implement one at a time behavior, the `entertoplayer` event can be used: + + +``` +tooltip.addEventListener(entertoplayer',() => { + for (const other of document.querySelectorAll('.tooltip')) { + other.classList.remove('tooltip'); + } +}); +``` + + +Some comments: + + + +* The `` proposal included the concept of “nested” popups - one popup could contain a nested popup (declared via DOM hierarchy, `popup` attribute, or `anchor` attribute), which would keep the parent popup from light-dismissing when the child popup opened. This might still be achievable via the same mechanisms. If we'd like this aspect of the behavior to also be configurable, perhaps the `dismiss-other` property can have an optional “except-nested” token that prevents nested elements from being dismissed. This likely needs more thought. + + +#### Focus Management + +See [this section](#focus-management-1). + + +#### Declarative Triggering (The `popup` Attribute) + +One feature provided by the `` proposal was the ability to use the `popup` content attribute on a triggering element (e.g. a button) to enable that element to show a `` when activated, without requiring Javascript. + +To implement this in a CSS-only context, the only way I can think of would be to modify the inline `style` attribute for the target element to include `position:top-layer`. That would be somewhat odd, though it would work, and would be relatively straightforward to implement. I'm not sure there are other similar precedents in the Web Platform. + +If this feature is maintained (via modifying inline styles or some other way), the `ariaHasPopup` property should be set appropriately. + + +#### Anchoring (The `anchor` Attribute) + +The anchoring solution here would seem to be identical to the [Attribute solution for anchoring](#anchoring-the-anchor-attribute-1). + + +#### Display Ordering and the `initiallyopen` Attribute + +Because of the light-dismiss behaviors, there needs to be a well-defined order of operations for adding elements to the top-layer. If multiple elements have `position:top-layer` and `light-dismiss:all`, then only the **last** of these elements should be eventually shown. It would seem that “last” in this context is determined by tree order, but there might be some odd scenarios. This needs more thought. + +The `` proposal had an `initiallyopen` attribute which could be used to show the `` upon page load. This would seem to be unnecessary, as this could be easily achieved using author CSS with `element {position: top-layer}`, assuming the ordering issues above are resolved. + + +#### Accessibility / Semantics + +Importantly, as the above proposals are entirely CSS-based presentational properties, none of them have **any semantic or accessibility impact**. I.e. the element being styled with `position: top-layer` will keep its existing semantics and AOM representation. + + +### Overall Pros and Cons + + +#### Pros + + + +* Solves the [Accessibility/Semantics problem](#alternative-dedicated-popup-element). +* Good DX: CSS is easy to understand and use. +* Works on any element. + + +#### Cons + +* This requires a “two class” top layer, with UA top layer elements such as modal `` and fullscreen elements always on top of “developer” top layer elements. This means these two UI features are incompatible. +* Unclear how to implement the `popup` declarative activation feature. + + +## Alternative: JavaScript API + +Generally, a JavaScript API is less preferable than an HTML/CSS based solution. And specifically, this approach suffers some of the same problems that the CSS approach has, namely that most of the one-at-a-time and light dismiss behavior is completely left to the developer to get right. Because this approach is more difficult to understand and code correctly, and doesn't offer any advantages relative to the HTML attribute solution, this approach was not used. + + +### API Shape + +#### Top Layer Presentation + +This can be implemented with a new Javascript function on Element:: + + +``` + +``` + +* This API is quite similar to the [requestFullScreen() API](https://fullscreen.spec.whatwg.org/#ref-for-dom-element-requestfullscreen%E2%91%A0). +* This allows any element to be added to the top-layer via Javascript. +* Similar to the other options presented in this document, admittance to the top-layer is not guaranteed or permanent - the UA can both deny an element access to the top-layer and can remove an element if needed. For example, when a modal dialog is shown or an element is made [fullscreen](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullScreen) - those changes might “kick out” other elements residing in the top-layer. +* Some element types should likely not be allowed into the top-layer. E.g. ``? Or any element that is currently fullscreen? + + +#### The :top-layer Pseudo Class + +See [this section](#the-top-layer-pseudo-class). + +#### Dismiss Behavior + +It would probably make the most sense to expose the various light dismiss options via an options bag on the `requestTopLayer()` function call: + + +``` + +``` + + +The [same questions apply](#dismiss-behavior-1) here about which dismissal options to support, and how to define them rigorously. + + +#### Focus Management + +While the [same comments from the Attribute section](#focus-management-1) might apply here, it would also be possible to expose the default focus behavior as an option in the `requestTopLayer()` function call: + + +``` + +``` + + +It would seem that the content attribute based solution [presented in the Attribute section](#focus-management-1) provides a more general purpose API that would likely be better than restricting this behavior to only the top-layer API. But perhaps there's a good reason for such a restriction. + + +#### Events + +The [Attribute solution for events](#events-1) would seem to work equally well here. Additionally, though, the `requestTopLayer()` function could return a Promise that resolves when the element is added to the top layer, or rejects if the element is not allowed to be promoted to the top layer. Whether this is actually useful would depend on whether the `requestTopLayer()` function promotes elements to the top layer synchronously or asynchronously. + + +#### Declarative Triggering (The `popup` Attribute) + +One feature provided by the `` proposal was the ability to use the `popup` content attribute on a triggering element (e.g. a button) to enable that element to show a `` when activated, without requiring Javascript. + +To implement this via the Javascript `requestTopLayer()` API, when the element with the popup attribute is activated by the user, the UA will simply call the `requestTopLayer()` function on the target element. Akin to the [HTML solution](#the-top-layer-pseudo-class), CSS will need to be used if the desire is to show a previously-invisible popup menu. + +There could also be other such declarative attributes, e.g. `tooltip`, which trigger the popup after a hover delay, in exactly the same way as the `popup` attribute. + +When the `popup` attribute is applied to an activating element, the `ariaHasPopup` property should be set appropriately by the UA. + + +#### Anchoring (The `anchor` Attribute) + +The [Attribute solution for anchoring](#anchoring-the-anchor-attribute-1) would seem to apply equally well to the Javascript based API. It is perhaps possible to also/instead add another option to the `requestTopLayer()` function call to indicate ancestor popups for this purpose, but that feels rather awkward. + + +#### Display Ordering and the `initiallyopen` Attribute + +The `` proposal had an `initiallyopen` attribute which could be used to show the `` upon page load. [That original proposal](https://open-ui.org/components/popup#the-initiallyopen-attribute) should still be usable in the context of a Javascript API, with very few changes. + + +#### Accessibility / Semantics + +Since the Javascript `requestTopLayer()` API does not change the content at all, and only impacts the element's presentation (top layer vs not top layer) after a call to `requestTopLayer()`, this will not have **any semantic or accessibility impact**. I.e. the element before and after the `requestTopLayer()` call will maintain its existing semantics and AOM representation. + + +### Javascript-based APIs + +There is a (strong?) bias among the group toward avoiding Javascript-only APIs, as they are more difficult to use, and the designer community is typically less comfortable and experienced with Javascript as compared to HTML/CSS. If it is possible to implement this “popup” functionality without **requiring** Javascript, that will be a win. + +It is possible that the `popup` declarative attribute gets around many/most of the standard use cases, and reduces the need to manually call `requestTopLayer()` from explicit Javascript. But it still seems like an HTML attribute is more easily understandable to designers. + + +### Overall Pros and Cons + + +#### Pros + + + +* Solves the Accessibility/Semantics problem +* Solves the [“removal from top layer” problem](#dismiss-behavior-2) inherent in the CSS solution. Since neither CSS nor HTML is affected by addition/removal from the top layer, there are no issues. +* Solves the [issue with the popup declarative attribute](#declarative-triggering-the-popup-attribute-1) in the CSS solution. +* Solves the [potential display ordering issues](#display-ordering-and-the-initiallyopen-attribute-1) raised by the CSS solution. +* Solves the [`` DX issues](#cons-1) inherent in the HTML content attribute solution. The `` controller can use the JS API to open and close the listbox, regardless of whether the listbox is UA-provided or developer-provided. +* Works on any element. + + +#### Cons + +* Javascript based APIs are less desirable than something based on HTML or CSS. +* Many footguns. diff --git a/research/src/pages/popup/popup.research.explainer-v1.mdx b/research/src/pages/popup/popup.research.explainer-v1.mdx new file mode 100644 index 000000000..add50d305 --- /dev/null +++ b/research/src/pages/popup/popup.research.explainer-v1.mdx @@ -0,0 +1,416 @@ +--- +name: Popup Element (Abandoned) +path: /components/popup.research.explainer-v1 +showInMenu: false +--- + +_This proposal first appeared on [Microsoft Edge explainers](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Popup/explainer.md). Open UI has taken up `` and related APIs as work items for incubation. Further development of these ideas will be driven in a draft specification within Open UI. The following represents the state of the original proposal as of March 18, 2021._ + +Authors: + +- [Ionel Popescu](https://github.com/ipopescu93) (Microsoft) +- [Melanie Richards](https://github.com/melanierichards) (Microsoft) +- [Dan Clark](https://github.com/dandclark) (Microsoft) +- [Bo Cupp](https://github.com/BoCupp) (Microsoft) +- [Mason Freed](https://github.com/mfreed7) (Google) +- [Yu Han](https://github.com/yuzhe-han) (Google) +- [Joey Arhar](https://github.com/josepharhar) (Google) +- [Greg Whitworth](https://github.com/gregwhitworth) (Salesforce) + + +# Note: This is an outdated proposal! + +Please see the updated version [here](/components/popup.research.explainer). + +## Introduction + +When building a web application, there are many cases in which an author needs to create transient user interface (UI) elements that are displayed on top of all other web app UI. These include user-interactive elements like action menus, form element suggestions, content pickers, and teaching UI. These paradigms will be collectively referred to as _popups_. + +![A popup menu displayed beneath a menu button; an explanatory popup with links pointing to a random button; and the popup portion of a select element](https://raw.githubusercontent.com/MicrosoftEdge/MSEdgeExplainers/main/Popup/use-cases.png) + +_Examples of popups may include action menus, teaching UI, or the listbox portion of a ` +
+
Option One
+ ... arrow down svg .. +
+ + + + +
+ Show more options + + +
+
+ +``` + +## Privacy and Security Considerations + +Freedom over the size and position of a `popup` could enable an author to spoof UI belonging to the browser or documents other than the `popup`’s document. For this reason the `popup` will be constrained as all other elements of the relevant document are, by clipping the element to the document's layout viewport. + +## Alternate Solutions Considered + +- **Extending the `dialog` element** with `popup`-specific methods and new options. This option wasn't pursued because it would result in a “mashed-up” API surface and collection of behaviors that seem better separate than together. Here are some examples of the semantic differences between the two elements to illustrate the point: + - `popup`s have lightweight UI that dismises automatically when the user interacts with other UI, or when a task is completed within the `popup` (such as selecting an option). + - `dialogs` are more persistent and are generally dismissed explicitly by the user. + - Only one `popup` can be shown at a time. + - More than one `dialog` can be presented at a time. + - `dialog` can be modal, such that user interaction with other UX elements is prevented. + - A `dialog` will dismiss a `popup` when shown but the converse isn’t true. +- **Introducing a `type` attribute for `popup`**, which would provide a set of default styles, user input behaviors, and accessibility semantics for various classes of popups. However, with the availability of the proposed HTML attributes and CSS property values, this approach did not provide much added authoring value past platform-managed accessibility semantics to the parent popup. Because this approach did not provide accessibility semantics or input behaviors for popup descendents, the authoring story was unclear in cases where the type of popup (e.g. `type="menu"`) must contain particular _descendents_ whose semantics could only be managed through ARIA (`role="menuitem"`) unless a new mechanism was proposed. + +## Open questions + +1. **Collision with CSS contain.** It’s worth noting that using the [`contain` CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/contain) on an ancestor of `popup` will prevent `popup` from being positioned and painted correctly. How common is this use case? How might the platform resolve this unintentional effect? + +2. **Could we require popups to use the DOM hierarchy for event propagation and establishing hierarchical popup relationships?** Elements used for popup UI today are frequently appended to the end of the DOM to ensure they appear on top of other UI. With the new capabilities of the `popup` element, that isn't necessary, yet we still assume in this proposal that DOM positioning of the `popup` needs to be separate from the anchor. One reason why that might still be needed is for anchor elements that can't accept a `popup` descendant, for example, image or input elements or custom-elements that expect a particular content model. Eliminating this requirement would also eliminate the complexity to modify the event propagation path based on the anchor attribute, and would make hierarchical relationships between popups clear just by observing the DOM hierarchy. + +3. **Should one of the attributes hoist up a `popup` in trees (e.g. accessibility trees)?** Today, it is common practice to include popup UI as a direct child of the root node. This practice is a workaround for top-layer positioning issues, and it is our hope that this proposal renders this practice obsolete. However, there might still be cases where an author includes a `popup` in a separate point in the DOM to its anchor/invoking element(s). We may want to explore reordering trees such that `popup` is moved into the proper context. Should the `popup` attribute and/or `anchor` attribute cause this reordering? What happens if both these attributes are present but refer to different elements? What happens if multiple `popup` attributes refer to the same `popup` element? + +4. **Show/hide or show/close?** This proposal introduces a symmetrical `show`/`hide` method pair on the proposed `popup` element. `dialog`, however, sets a precedent for a `show` and `close` method pairing. That seemed less intuitive, but perhaps the existing pattern should be followed. Alternatively, the platform could introduce `hide` on `dialog` and consider `close` deprecated. + +## Areas for exploration + +- **Focus trapping:** the [`inert` attribute](https://whatpr.org/html/4288/interaction.html#the-inert-attribute) enables authors to mark portions of a document as inert, such that user input events are ignored. Inverting this model, new primitives could enable focus trapping with parts of a document, e.g. a `popup`. New focus trapping primitives could be useful in cases where the tab cycle should be constrained to the `popup`, but the rest of the document would receive other types of user input. + +- **Animating state transitions:** applying animations and transitions to interactive elements’ show/hide states can be difficult. For example, to apply a CSS transition the element must first produce an initial box before its properties can be transitioned to new values. That requires a two step process to first show the element, and in a subsequent frame, initiate a transition by applying a class. Likewise, since the browser manages the visibility of the popup for light dismiss behaviors, it is impossible to apply a close animation. To address this issue perhaps the answer is to invent a new CSS animation primitive that is triggered when an element stops producing a box. + +## Appendix + +### The `hidden` attribute + +This proposal specifies that, similarly to the `dialog` element, the `open` attribute can be used to show a `popup`. Currently, authors are advised to add a `hidden` attribute to `dialog` when hiding it, as there are [some quirks with removing the `open` attribute](https://html.spec.whatwg.org/multipage/interactive-elements.html#the-dialog-element). Rather than porting over this behavior to `popup`, it would be ideal to [adjust the behavior on `dialog`](https://github.com/whatwg/html/issues/5802). As a result and to provide simpler authoring, we are proposing that authors solely remove/add the `open` attribute in order to toggle visibility of a `popup`, as opposed to introducing the `hidden` attribute to this new element. + +### Anchoring and event bubbling + +In a previous version of this document, we proposed that the hierarchy created by the `anchor` attribute relationship affects the event propagation path. With the introduction of a separate `popup` attribute which creates an invocation relationship, it is less clear whether event bubbling should be changed as a result of the `popup` attribute and/or the `anchor` attribute. + +This behavior as previously proposed adds complexity to the platform, and it is not clear whether there is enough value to authors for the platform to take on that complexity. We welcome feedback on this point and preserve the previous proposal here. + +#### Example of event bubbling + +In the markup below, a table with many rows is rendered, each of which displays a custom popup filled with commands when right-clicked. The popup is defined once and its anchor attribute is adjusted so that it is shown aligned with the table row when the contextmenu event is received. + +After a command is selected from the menu, the menu dispatches a custom command event which is then handled by the table row. The table row receives the event even though it isn’t a DOM ancester of the popup. This is because the event target parent of a popup is its anchor element. + +```html + + ... + ... + ... + ... +
+ + + + ... + + +``` + +Note: if event bubbling remains unchanged by the `anchor` attribute, authors in this case would need to query for the `popup`’s anchor element and dispatch the event from that element. So, `e.currentTarget.dispatchEvent(new CommandEvent(e.currentTarget.id))` becomes `bugCommands.anchor.dispatchEvent(new CommandEvent(e.currentTarget.id))`. diff --git a/research/src/pages/popup/popup.research.explainer.mdx b/research/src/pages/popup/popup.research.explainer.mdx index 696065b72..9f4de050e 100644 --- a/research/src/pages/popup/popup.research.explainer.mdx +++ b/research/src/pages/popup/popup.research.explainer.mdx @@ -1,415 +1,408 @@ --- -name: Enabling Popups, Initial Explainer +menu: Proposals +name: Popup API (Explainer) path: /components/popup.research.explainer -showInMenu: false +pathToResearch: /components/popup.research --- -_This proposal first appeared on [Microsoft Edge explainers](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Popup/explainer.md). Open UI has taken up `` and related APIs as work items for incubation. Further development of these ideas will be driven in a draft specification within Open UI. The following represents the state of the original proposal as of March 18, 2021._ +- [@mfreed7](https://github.com/mfreed7), [@scottaohara](https://github.com/scottaohara), [@BoCupp-Microsoft](https://github.com/BoCupp-Microsoft), [@domenic](https://github.com/domenic), [@gregwhitworth](https://github.com/gregwhitworth), [@chrishtr](https://github.com/chrishtr), [@dandclark](https://github.com/dandclark), [@una](https://github.com/una), [@smhigley](https://github.com/smhigley), [@aleventhal](https://github.com/aleventhal) +- March 16, 2022 + + + +## Table of Contents + +- [Background](#background) + - [Goals](#goals) + - [See Also](#see-also) +- [API Shape](#api-shape) + - [HTML Content Attribute](#html-content-attribute) + - [Declarative Trigger (the `triggerpopup` attribute)](#declarative-trigger-the-triggerpopup-attribute) + - [Dismiss Behavior](#dismiss-behavior) + - [Classes of UI - Dismiss Behavior and Interactions](#classes-of-ui---dismiss-behavior-and-interactions) + - [Events](#events) + - [Focus Management](#focus-management) + - [Anchoring (the `anchor` Attribute)](#anchoring-the-anchor-attribute) + - [Display Ordering](#display-ordering) + - [Accessibility / Semantics](#accessibility--semantics) + - [Example Use Cases](#example-use-cases) + - [Pros and Cons](#pros-and-cons) +- [Additional Considerations](#additional-considerations) + - [Current Top Layer Behavior](#current-top-layer-behavior) + - [Shadow DOM](#shadow-dom) + - [Exceeding the Frame Bounds](#exceeding-the-frame-bounds) + - [Eventual Single-Purpose Elements](#eventual-single-purpose-elements) +- [Other Alternatives Considered](#other-alternatives-considered) + + + +# Background + +There is a need in the Web Platform for an API to create "popup UI". This is a general class of UI that always appear on top of all other content, and have both one-at-a-time and "light-dismiss" behaviors. This document proposes a set of APIs to make this type of UI easy to build. -Authors: -- [Ionel Popescu](https://github.com/ipopescu93) (Microsoft) -- [Melanie Richards](https://github.com/melanierichards) (Microsoft) -- [Dan Clark](https://github.com/dandclark) (Microsoft) -- [Bo Cupp](https://github.com/BoCupp) (Microsoft) -- [Mason Freed](https://github.com/mfreed7) (Google) -- [Yu Han](https://github.com/yuzhe-han) (Google) -- [Joey Arhar](https://github.com/josepharhar) (Google) -- [Greg Whitworth](https://github.com/gregwhitworth) (Salesforce) +## Goals -## Status of this Document +Here are the goals for this API (borrowed liberally from the [`` element explainer](https://open-ui.org/components/popup.research.explainer)): -This document is a starting point for engaging the community and standards bodies in developing collaborative solutions fit for standardization. As the solutions to problems described in this document progress along the standards-track, we will retain this document as an archive and use this section to keep the community up-to-date with the most current standards venue and content location of future work and discussions. +* Allow any* element and its (arbitrary) descendants to be rendered on top of **all other content** in the host web application. +* Include **“light dismiss” management functionality**, to remove the element/descendants from the top-layer upon certain actions such as hitting Esc (or any [close signal](https://wicg.github.io/close-watcher/#close-signal)) or clicking outside the element bounds. +* Allow this “top layer” content to be fully styled, including properties which require compositing with other layers of the host web application (e.g. the box-shadow or backdrop-filter CSS properties). +* Allow these top layer elements to reside at semantically-relevant positions in the DOM. I.e. it should not be required to re-parent a top layer element as the last child of the `document.body` simply to escape ancestor containment and transforms. +* Allow this “top layer” content to be sized and positioned to the author's discretion. +* Include an appropriate user input and focus management experience, with flexibility to modify behaviors such as initial focus. +* **Accessible by default**, with the ability to further extend semantics/behaviors as needed for the author's specific use case. +* Avoid developer footguns, such as improper stacking of dialogs and popups, and incorrect accessibility mappings. +* Avoid the need for Javascript for the common cases. -## Introduction +*There may need to be some limitations in some cases. -When building a web application, there are many cases in which an author needs to create transient user interface (UI) elements that are displayed on top of all other web app UI. These include user-interactive elements like action menus, form element suggestions, content pickers, and teaching UI. These paradigms will be collectively referred to as _popups_. -![A popup menu displayed beneath a menu button; an explanatory popup with links pointing to a random button; and the popup portion of a select element](https://raw.githubusercontent.com/MicrosoftEdge/MSEdgeExplainers/main/Popup/use-cases.png) +## See Also -_Examples of popups may include action menus, teaching UI, or the listbox portion of a ` -
-
Option One
- ... arrow down svg .. -
- - - - -
- Show more options - - -
-
- -``` +This table documents what **currently happens** in the Chromium rendering engine, which is the only one to support any top-layer elements besides fullscreen. In particular, it documents the current `` element prototype, which is just one possibility for the general “popup” API being described here. -## Privacy and Security Considerations +**Chromium 99.x behavior** -Freedom over the size and position of a `popup` could enable an author to spoof UI belonging to the browser or documents other than the `popup`’s document. For this reason the `popup` will be constrained as all other elements of the relevant document are, by clipping the element to the document's layout viewport. -## Alternate Solutions Considered + + + + + + +
Second Element
First ElementFull screenModal dialog`<popup>` element
Full screenThe second fullscreen element kicks the first one out of the top layer. ESC closes the second fullscreen element.Full screen stays visible, modal is displayed above fullscreen. ESC closes fullscreen first, second ESC closes dialog (backwards).Full screen stays visible, popup is displayed above fullscreen. ESC closes fullscreen first, second ESC closes popup (backwards).
Modal dialogFull screen is displayed on top of modal, both are in the top layer. ESC closes full screen, second ESC closes dialog.Both dialogs are shown, first under second. First ESC closes second dialog, then first.Both are shown, dialog is under popup. Hitting ESC once closes both of them.
`<popup>` elementFull screen is displayed on top of popup, both are in the top layer. ESC closes full screen, second ESC closes popup.The dialog opening dismisses the popup. Hitting ESC closes the dialog.The second popup dismisses the first (assuming they're not “ancestors” via DOM tree or anchor/popup attributes). Hitting ESC closes the popup.
-- **Extending the `dialog` element** with `popup`-specific methods and new options. This option wasn't pursued because it would result in a “mashed-up” API surface and collection of behaviors that seem better separate than together. Here are some examples of the semantic differences between the two elements to illustrate the point: - - `popup`s have lightweight UI that dismises automatically when the user interacts with other UI, or when a task is completed within the `popup` (such as selecting an option). - - `dialogs` are more persistent and are generally dismissed explicitly by the user. - - Only one `popup` can be shown at a time. - - More than one `dialog` can be presented at a time. - - `dialog` can be modal, such that user interaction with other UX elements is prevented. - - A `dialog` will dismiss a `popup` when shown but the converse isn’t true. -- **Introducing a `type` attribute for `popup`**, which would provide a set of default styles, user input behaviors, and accessibility semantics for various classes of popups. However, with the availability of the proposed HTML attributes and CSS property values, this approach did not provide much added authoring value past platform-managed accessibility semantics to the parent popup. Because this approach did not provide accessibility semantics or input behaviors for popup descendents, the authoring story was unclear in cases where the type of popup (e.g. `type="menu"`) must contain particular _descendents_ whose semantics could only be managed through ARIA (`role="menuitem"`) unless a new mechanism was proposed. -## Open questions +Note that the current fullscreen and `` behavior does not prevent both types of elements from being in the top layer at once. In other words, there is currently no “one-at-a-time” managment of the top layer, other than the handling of the ESC key. In some cases the keyboard interaction pattern can be a bit confusing. For example, in several cases, hitting ESC first closes the element on the **bottom**, and a second ESC closes the element on the “top”. This is on purpose, for security reasons ([specified here](https://wicg.github.io/close-watcher/#close-signal-steps)): the ESC key must always close the fullscreen element and should not be cancellable. -1. **Collision with CSS contain.** It’s worth noting that using the [`contain` CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/contain) on an ancestor of `popup` will prevent `popup` from being positioned and painted correctly. How common is this use case? How might the platform resolve this unintentional effect? +Generally, [per spec](https://fullscreen.spec.whatwg.org/#new-stacking-layer), when there are multiple elements in the top layer, they are rendered in the order they were added to the top layer set. Each of these elements forms a stacking context, meaning z-index cannot be used to change this painting order. -2. **Could we require popups to use the DOM hierarchy for event propagation and establishing hierarchical popup relationships?** Elements used for popup UI today are frequently appended to the end of the DOM to ensure they appear on top of other UI. With the new capabilities of the `popup` element, that isn't necessary, yet we still assume in this proposal that DOM positioning of the `popup` needs to be separate from the anchor. One reason why that might still be needed is for anchor elements that can't accept a `popup` descendant, for example, image or input elements or custom-elements that expect a particular content model. Eliminating this requirement would also eliminate the complexity to modify the event propagation path based on the anchor attribute, and would make hierarchical relationships between popups clear just by observing the DOM hierarchy. -3. **Should one of the attributes hoist up a `popup` in trees (e.g. accessibility trees)?** Today, it is common practice to include popup UI as a direct child of the root node. This practice is a workaround for top-layer positioning issues, and it is our hope that this proposal renders this practice obsolete. However, there might still be cases where an author includes a `popup` in a separate point in the DOM to its anchor/invoking element(s). We may want to explore reordering trees such that `popup` is moved into the proper context. Should the `popup` attribute and/or `anchor` attribute cause this reordering? What happens if both these attributes are present but refer to different elements? What happens if multiple `popup` attributes refer to the same `popup` element? -4. **Show/hide or show/close?** This proposal introduces a symmetrical `show`/`hide` method pair on the proposed `popup` element. `dialog`, however, sets a precedent for a `show` and `close` method pairing. That seemed less intuitive, but perhaps the existing pattern should be followed. Alternatively, the platform could introduce `hide` on `dialog` and consider `close` deprecated. +## Shadow DOM -## Areas for exploration +Some thought needs to be given to what happens if an element within a shadow root uses this API to move a shadow-DOM-contained element to the top layer. One use case of such an element would be a custom element that wraps a popup type UI element, such as a ``. Should it be “ok” for a shadow element (potentially inside even a closed shadow root) to be promoted to the top layer like this? Or should it be a requirement that the light-DOM element (e.g. the `` element) itself be the one to get promoted to the top layer? -- **Focus trapping:** the [`inert` attribute](https://whatpr.org/html/4288/interaction.html#the-inert-attribute) enables authors to mark portions of a document as inert, such that user input events are ignored. Inverting this model, new primitives could enable focus trapping with parts of a document, e.g. a `popup`. New focus trapping primitives could be useful in cases where the tab cycle should be constrained to the `popup`, but the rest of the document would receive other types of user input. +Since the rendering output from a shadow host **is already** its shadow DOM content only, it would seem totally appropriate for shadow-contained elements to be allowed to move to the top layer, since the top layer is very similar to z-index and is just a layout convenience. It also seems considerably more ergonomic to allow this, rather than requiring the top-layer API be used at the highest light-DOM element containing the desired content. There are even cases where this wouldn't make sense or be possible, such as a web component containing the entire page, ``. In that case, it wouldn't be possible for anything contained in the app to use the top layer API. -- **Animating state transitions:** applying animations and transitions to interactive elements’ show/hide states can be difficult. For example, to apply a CSS transition the element must first produce an initial box before its properties can be transitioned to new values. That requires a two step process to first show the element, and in a subsequent frame, initiate a transition by applying a class. Likewise, since the browser manages the visibility of the popup for light dismiss behaviors, it is impossible to apply a close animation. To address this issue perhaps the answer is to invent a new CSS animation primitive that is triggered when an element stops producing a box. +It would seem, from the discussion above, that any element, including shadow-contained elements, **should be allowed to use this API**. -## Appendix +## Exceeding the Frame Bounds -### The `hidden` attribute +Allowing a popup/top-layer element to exceed the bounds of its containing frame poses a serious security risk: such an element could spoof browser UI or containing page content. While the [original `` proposal](https://open-ui.org/components/popup.research.explainer#goals) did not discuss this issue, the [`` proposal](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/ControlUICustomization/explainer.md#security) does have a specific section at least mentioning this issue. While it is possible to allow exceeding frame bounds in some cases, e.g. with the fullscreen API, great care must be taken in these cases to ensure user safety. It would seem difficult to allow an arbitrary element to exceed frame bounds using this (popup/top-layer) proposal. But perhaps there are safe ways to allow this behavior. More brainstorming is needed. -This proposal specifies that, similarly to the `dialog` element, the `open` attribute can be used to show a `popup`. Currently, authors are advised to add a `hidden` attribute to `dialog` when hiding it, as there are [some quirks with removing the `open` attribute](https://html.spec.whatwg.org/multipage/interactive-elements.html#the-dialog-element). Rather than porting over this behavior to `popup`, it would be ideal to [adjust the behavior on `dialog`](https://github.com/whatwg/html/issues/5802). As a result and to provide simpler authoring, we are proposing that authors solely remove/add the `open` attribute in order to toggle visibility of a `popup`, as opposed to introducing the `hidden` attribute to this new element. +In the interim, two use counters were added to measure how often this type of behavior might be needed. They are approximations, as they merely measure the total number of times a “popup” is shown (including `` color picker, and `` date/time picker), and the total number of times those popups exceed the owner frame bounds. Data can be found here: -### Anchoring and event bubbling -In a previous version of this document, we proposed that the hierarchy created by the `anchor` attribute relationship affects the event propagation path. With the introduction of a separate `popup` attribute which creates an invocation relationship, it is less clear whether event bubbling should be changed as a result of the `popup` attribute and/or the `anchor` attribute. -This behavior as previously proposed adds complexity to the platform, and it is not clear whether there is enough value to authors for the platform to take on that complexity. We welcome feedback on this point and preserve the previous proposal here. +* Total popups shown: [0.7% of page loads](https://chromestatus.com/metrics/feature/timeline/popularity/3298) +* Popups appeared outside frame bounds: [0.08% of page loads](https://chromestatus.com/metrics/feature/timeline/popularity/3299) -#### Example of event bubbling +So about 11% of all popups currently exceed their owner frame bounds. That should be considered a rough upper bound, as it is possible that some of those popups **could** have fit within their frame if an attempt was made to do so, but they just happened to exceed the bounds anyway. -In the markup below, a table with many rows is rendered, each of which displays a custom popup filled with commands when right-clicked. The popup is defined once and its anchor attribute is adjusted so that it is shown aligned with the table row when the contextmenu event is received. -After a command is selected from the menu, the menu dispatches a custom command event which is then handled by the table row. The table row receives the event even though it isn’t a DOM ancester of the popup. This is because the event target parent of a popup is its anchor element. +## Eventual Single-Purpose Elements -```html - - ... - ... - ... - ... -
- - - - ... - - -``` +There might come a time, sooner or later, where a new HTML element is desired which combines strong semantics and purpose-built behaviors. For example, a `` or `` element. Those elements could be relatively easily built via the APIs proposed in this document. For example, a `` element could be defined to have `role=tooltip` and `popup=hint`, and therefore re-use this Popup API for always-on-top rendering, one-at-a-time management, and light dismiss. In other words, these new elements could be *explained* in terms of the lower-level primitives being proposed for this API. + + +# Other Alternatives Considered + +To achieve the [goals](#goals) of this project, a number of approaches could have been used: + +* An HTML content attribute (this proposal). +* A dedicated `` element. +* A CSS property. +* A Javascript API. + +Each of these options is significantly different from the others. To properly evaluate them, each option was fleshed out in some detail. Please see this document for the details of that effort: + + * [Other Alternatives Considered](/components/popup.proposal.alternatives) -Note: if event bubbling remains unchanged by the `anchor` attribute, authors in this case would need to query for the `popup`’s anchor element and dispatch the event from that element. So, `e.currentTarget.dispatchEvent(new CommandEvent(e.currentTarget.id))` becomes `bugCommands.anchor.dispatchEvent(new CommandEvent(e.currentTarget.id))`. +That document discusses the pros and cons for each alternative. After exploring these options, the [HTML content attribute](#html-content-attribute) approach [was determined](https://github.com/openui/open-ui/issues/455#issuecomment-1050172067) to be the best overall. diff --git a/research/src/pages/popup/popup.research.mdx b/research/src/pages/popup/popup.research.mdx index 67964e604..d11077214 100644 --- a/research/src/pages/popup/popup.research.mdx +++ b/research/src/pages/popup/popup.research.mdx @@ -10,7 +10,8 @@ This research page gathers together various subclasses of popups into one collec ## Additional research -- [Enabling Popups, Initial Explainer](/components/popup.research.explainer) +- [Popup attribute explainer](/components/popup.research.explainer) +- [Original Popup Element Explainer](/components/popup.research.explainer-v1) ## Behaviors