Replies: 11 comments 5 replies
-
I have found the imperative API to be pretty useful in development. I'm curious to know more about the style and layout delivery constraints mentioned here. I find the imperative Overlay API to be nice to use in situations where UI is overlaid that isn't necessarily coupled to a specific UI component such as toast type notifications/ popups that may be triggered by shared services. For example, a router might trigger a dialog to confirm the decision to leave a page. With the current Overlay system, I also believe consumers must use the imperative approach if they want to leverage a VirtualTrigger. Are we planning to move away from VirtualTriggers? If you do plan on keeping the Imperative API in the Overlay rewrite it would be nice if SWC could provide helpers for devs using Lit. For example for imperative modals:
|
Beta Was this translation helpful? Give feedback.
-
@Westbrook it looks like LrW is primarily using The other small concern I have here is the potential for stacking context bugs (particularly on mobile browsers where I've seen issues in the past, as they tend to take more heavy-handed approach to gpu optimization). This might mean using a lamer workaround beyond the ones you've listed for css layering like a css transform to force the z position to be higher. I'm confident we'll be able to work around and report any issues that come up though. |
Beta Was this translation helpful? Give feedback.
-
Ensure that the management of the <sp-overlay>
<some-non-swc-element>
#shadow-root
<sp-popover>...</sp-popover>
</some-non-swc-element>
</sp-overlay> Here the consumer needs to manage the relationship between the |
Beta Was this translation helpful? Give feedback.
-
Should we expand |
Beta Was this translation helpful? Give feedback.
-
It would be nice if client applications could optionally specify a priority stacking order on their Spectrum overlays. This can be useful in cases where applications might trigger overlays to open programmatically and some overlays might have higher priority than others. For example, a blocking lost connection takeover modal always being placed on top. It can be tricky to orchestrate this at the application level especially when working on large apps being developed by multiple distributed teams. I imagine this priority could come in the form of a simple number:
or perhaps it might be interesting to let client applications plugin to the Overlay system in some manner to define their own own overlay stacking strategy. |
Beta Was this translation helpful? Give feedback.
-
More about |
Beta Was this translation helpful? Give feedback.
-
Something that I think it is important to communicate, is to make sure that the events include the target that triggered the event. Currently if you have a page, several tooltips, popovers, etc, there is no way to identify which Overlay triggered the event. You can sometimes rely on the interaction type (if they are different), but if not there is no obvious way to recognize. Ideally event.target or event.relatedTarget would point to the Overlay that triggered the event. |
Beta Was this translation helpful? Give feedback.
-
Progress Update
|
Beta Was this translation helpful? Give feedback.
-
It sounds like the new |
Beta Was this translation helpful? Give feedback.
-
Progress UpdateA Release Candidate for this work has been released as of July 12th, 2023. Starting with version Learn more about leveraging these updates via: Please share any feedback from your experience leveraging this RC release early and often so we can continue towards our current goal of a July release of this API. |
Beta Was this translation helpful? Give feedback.
-
This has shipped! |
Beta Was this translation helpful? Give feedback.
-
Table Of Contents
Summary
New developments in the web platform provide an opportunity to streamline one of the most important APIs of Spectrum Web Components: overlays. The Overlay system powers every instance of content that visually obscures others, including tooltips, dialogs, pickers, and menus. It also incurs a high maintenance and support cost; overlay causes more issues than any other API.
Currently, Overlay implements a "user-space" solution by reparenting elements directly into the document's body. This has been the only option to guarantee correct visual presentation. However, new browser features like
<dialog>
and[popover]
unlock the option of overlaying content visually without mutating the DOM.This RFC proposes shifting both the public API and the internal implementation to seize this opportunity. It discusses these new APIs, how the Overlay API will leverage them, the use-cases they won't cover, and how consumers will be able to adopt this functionality.
Basic Example
The central thesis of this new API is that we should leverage browser primitives wherever possible, while also preparing for the presence of in-development browser primitives when they become available. In this way, we will focus on consumption of the
<dialog>
element and thepopover
attribute; APIs surfaced by the browser in a declarative manner. We will also focus on surfacing our orchestrations and speculative polyfilling of these capabilities in a declarative manner, which will take the form of the<sp-overlay>
element. To support transition from our current imperative API, we will also surface this functionality imperatively. However, the imperative API will rely on injecting an<sp-overlay>
element into the DOM tree from which you would like to overlay content, which has the possibility of negatively affecting style delivery or layout in your content. When an imperative API is preferred, consumption of the<sp-overlay>
element will be more predictable if you leveragedocument.createElement(‘sp-overlay’)
ornew Overlay()
directly. With these things in mind, we highly recommend declarative consumption of the new Overlay API and suggest that you partner with us early and often on ideating paths towards this usage.Declarative modal dialog
Declarative [popover] or “overlay” (attribute API)
Imperative modal dialog
Imperative [popover]
Motivation
Overlaid content in the browser is hard. Before the browser APIs that we will be leveraging to power this work, really solid ways of handling this content across all use cases were hard to find. While we’ve had quality success to date with our current approach, we believe that embracing new and pending browser APIs will go a long way in us and our consumers finding even more success going into the future. We see this being possible by the following motivations:
The overlay system’s outsized number of issues & support is largely driven by its current need to reparent elements in the DOM. It has a high maintenance burden and low stability due to a large amount of user-space code that could now be deleted in favor of platform-provided functionality.
Detailed Design
Imperative API
The fill imperative API for opening an overlay is as follows:
Options
<dialog>.showModal()
based (‘modal’ or ‘page’):, the ‘page’ value prevents the defaultescape
functionality to close the overlay, or to be[popover].showPopover()
based, and whichpopover
value to use.Return value
This API will return a reference to the
<sp-overlay>
element that it creates. This will give consuming applications full access to the API of the<sp-overlay>
wrapping their content. To smooth adoption, we will be accepting the oldOverlay.open()
arguments for a short conversion period, and could see altering the return value when that call signature is leveraged in order to further reduce the changes needed to move, initially, to this new API.element
Attributes
@
symbol to include the interaction (click
|longpress
|hover
) to bind opening/closing the overlay on that element. This looks like the following:trigger=”triggerID”
would locate[id=”triggerID”]
in the same DOM tree for use in positioning the overlaid contenttrigger=”triggerID@click”
would locate[id=”triggerID”]
in the same DOM tree and then bind the open of the overlay to theclick
eventtrigger=”triggerID@longpress”
would locate[id=”triggerID”]
in the same DOM tree and then bind the open of the overlay to thelongpress
eventtrigger=”triggerID@hover”
would locate[id=”triggerID”]
in the same DOM tree and then bind the open/close of the overlay to the events that complete the “hover” contract<dialog>.showModal()
based (‘modal’ or ‘page’):, the ‘page’ value prevents the defaultescape
functionality to close the overlay, or to be[popover].showPopover()
based, and whichpopover
value to use.Properties
<sp-overlay>
elementEvents
Drawbacks/Constraints
While the
<dialog>
element is rather well supported by browsers (https://caniuse.com/dialog), meaning that little to no polyfilling or fallback support will be needed, the[popover]
attribute is still pre-agreement (https://open-ui.org/components/popup.research.explainer) and will feature contexts that it just cannot support correctly regardless of the fallback approach until it is supported natively in browsers. Some of these contexts have a “consumption workaround”, or things consumers can do to prevent them from affecting their applications, and others are hopefully minor edge cases, but they are as follows.Complex Layering
This situation affects content that could be overlain that exists within ancestor content that has been provided a value for the CSS
position
andz-index
properties that sits adjacent to content that has been provided a functioningz-index
that is higher than the ancestor content.CSS Containment
This situation affects content with an ancestor that leverages the CSS property
contain
with a value that is or impliespaint
. In the case that the overlay should display within that ancestor, there is likely not to be an issue, but containing paint means that the overlay cannot appear outside of that ancestor, which may be unexpected.CSS Clip-path
Overlay content delivered within an ancestor element that leverages the CSS property
clip-path
has a chance of being clipped itself. This feels like the least likely situation as theclip-path
property is helpful in only very specific situations.Working around CSS issues
A pragmatic workaround here is to draw a seam between what can really be contained in a given rect, vs. containers that require a permeable boundary. In the above examples, consider moving overflow, containment, or clip-path management into a separate child element’, to continue to benefit from performance optimizations without breaking the overlay presentation.
This would mean instead of:
You could deliver your UI as:
Not all UIs will benefit from this approach, but in many cases, it will allow for mitigating the negative side effects of leveraging
<dialog>
and[popover]
before they are fully supported in browsers.Alternatives
Maintain & better document the current API
A subset of our objectives may be reachable through more complete documentation and examples of the current API. While enhanced documentation is a target of all of our work, we do realize that the depth of complexity in the current Overlay API leaves much to be desired and has disadvantaged our consumers in more ways than one.
Evolve the current API, maintaining core behavior
We’ve discussed ways that the current API could be evolved to achieve a different subset of our objectives.
The current Overlay API uses content reparenting to force overlay content to the end of the document to fully escape clipping and layering issues that can occur due to various CSS incantations. However, reparenting causes concentration as to the application of styles onto that content. See this documentation for more information, and follow these issue links for a better understanding of the issues that consumers have faced in the past.
Adoption strategy
In as many cases as possible, we’d like this update to the Overlay API to not be a breaking change for our consumers. When leveraging the imperative API, you will no longer be returned a single
close()
method, but instead, an<sp-overlay>
element that has aclose()
method. We will be updating the internals of<overlay-trigger>
to leverage the<sp-overlay>
element and translatingOverlay.open(owner: HTMLElement, interaction: TriggerInteractions, overlayElement: HTMLElement, options: OverlayOptions)
calls toOverlay.open(target: HTMLElement, options: OverlayV2Options)
under the covers. In some cases, this may subject consumers of this API to the Drawbacks/Constraints outlined above, however, we look to minimize the occurrence of this situation by working with our partners through a Canary release process to find ways to alleviate these issues in their applications.While the initial focus will be one-for-one support of current consumption, we will be suggesting that consumers move towards direct consumption of the declarative
<sp-overlay>
element instead of<overlay-trigger>
or the imperative API in new features immediately, and in their existing feature surfaces at their convenience. With the availability of<sp-overlay>
we believe that taking greater control of imperative injection of this element into their application will benefit consumers greater than any future developments of theOverlay.open()
API could and suggest that is they must deliver overlay content imperatively they leverage something like the following to do so:Were any of our Client Contributors to have experience in tools like codemods or similar, we’d greatly appreciate their input on ways that we could leverage those capabilities to simplify this process for everyone involved.
How do we educate people?
The following will be made available to support consumers getting up to speed on the new APIs:
Open Questions
[popover]
Origin Trial on Chromium browsers to reduce our dependency on polyfills and fallbacks? Is it possible to have an “SWC Origin Trial” or does each consuming product need to do this for themselves?[popover=”hint”]
has been pushed to V2 of the browser API here, ismanual
a fully acceptable path forward for “tooltip” like overlays?sp-opened
andsp-closed
events wide enough that we should continue to dispatch these events for some time? Or possibly make them part of the new API?References
Related Issues
#424 #511 #518 #606 #617 #709 #710 #803 #848 #866 #1055 #1094 #1133 #1249 #1267 #1284 #1289 #1323 #1331 #1360 #1437 #1512 #1540 #1559 #1783 #1831 #1853 #1876 #1897 #2026 #2067 #2068 #2082 #2197 #2198 #2282 #2360 #2502 #2536 #2539 #2568 #2599 #2625 #2646 #2647 #2657 #2693
Beta Was this translation helpful? Give feedback.
All reactions