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

docs: update portal cookbook with solved problems #5600

Merged
merged 2 commits into from
Dec 18, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 42 additions & 7 deletions packages/docs/src/routes/docs/cookbook/portal/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,52 @@ import CodeSandbox, {CodeFile} from '../../../../components/code-sandbox/index.t

# Portal

A common problem in front-end development is to pop up a modal dialog from a component. The complication is that the modal dialog needs to be rendered in a different part of the DOM tree, and the component that triggers the modal needs to have a way to affect the location of rendering.
In front-end development, sometimes we need to display a component (like a modal or tooltip) in a different place from where it was triggered. The issue is that the UI element needs to be rendered in a different part of the DOM tree, and the component that triggers the element needs to have a way to affect the location of rendering.

In other frameworks, this is often solved by dedicated API such as [`createPortal()`](https://react.dev/reference/react-dom/createPortal). However such APIs don't work well with server-side rendering and so an alternative approach is needed.
In other frameworks, this is often solved by a dedicated API such as [`createPortal()`](https://react.dev/reference/react-dom/createPortal). However such APIs don't work well with server-side rendering and so an alternative approach is needed.

## Alternatives
## Qwik UI

You may want to consider these modern browser alternatives to modals:
- https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog
- https://developer.chrome.com/blog/introducing-popover-api/
Luckily, there is native behavior that handles this for us, called the [top layer](https://developer.chrome.com/blog/what-is-the-top-layer). The Qwik UI team has done an awesome job of filling in the gaps, and allowing us to use this behavior in production.

## Problem
### Modals

We use modals when we do not want the user to interact with the rest of the page. The rest of the content is inert, or unable to be interacted with.

[Qwik UI's modal component](https://qwikui.com/docs/headless/modal/) uses the dialog element's [showModal](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal) method, which is well-supported in browsers and automatically handles placing UI outside of the HTML Document.

It also includes behavior such as focus and scroll locking, alert dialogs, automatic entry and exit animation support, and backdrop animations. At the time of writing, support for the dialog element is currently at 96%.

### Non-modal UI

If the UI element can interact with the rest of the page, then it is not modal.

Some examples of non-modal components are:
- Popovers
- Overlays
- Toasts
- Tooltips
- Dropdown menus
- Selects
- Comboboxes

[MDN's popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) replaces the need for portals in non-modal components. Support is also in every major browser. At the time of writing, it's at ~73%.

Qwik UI has taken it upon themselves by providing a polyfill with feature parity to the native spec. You can use the Popover API's behavior in production today with [Qwik UI's Popover](https://qwikui.com/docs/headless/popover/) component.

In the case of components like a select or combobox, Qwik UI also provides the abiltiy to opt-in to "floating" behavior. For example, when a listbox anchors to an input element. You can do so by adding `floating={true}` to your Popover component. This will execute a bit of extra javascript needed for floating behavior.

It is intentionally opt-in, at some point the CSS Anchor API will provide a native solution, and so there should be an easy migration path when that receives more general support.

> Because these solutions are built on top of the native specs, that also means there's less javascript we need to prefetch, and therefore less work that needs to be done!
Both Qwik UI's popover and modal components can be used regardless of meta-framework or microfrontend, as long as there is support for Qwik.

## Custom Portals

If the behavior of the above components do not fit the use case, there is also the ability to create a custom portal component in Qwik. We'll create a modal component from scratch.

> The following is an SSR portal implementation using Qwik City. If you are using multiple frontend frameworks alongside Qwik, you may prefer a [React-like portal implementation](https://github.com/qwikifiers/qwik-ui/blob/main/packages/kit-headless/src/components/popover/popover-impl.tsx#L42).
The fundamental problems to solve are:
1. decide where the popup should be rendered in the application. (Let's call this `<Portal>`)
Expand Down
Loading