sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
76.64k stars 3.96k forks source link

`Portal` Component #11301

Closed huntabyte closed 1 week ago

huntabyte commented 1 week ago

Describe the problem

Currently, Svelte lacks a built-in way to render a component's children at a different location in the DOM tree from where the component itself is mounted. This capability is often referred to as "portalling" or "teleporting" and is useful in a variety of scenarios:

While it's possible to implement portalling in Svelte currently using a custom action, it has some downsides:

1. Extra DOM Node

Actions would require a DOM node to have the use:portal action, so if you wanted to turn it into a component, capable of wrapping arbitrary children like so:

<Portal>
    <span> This is some content I want portalled to the body </span>
</Portal>

The result would look something like this:

<body>
    <div id="portal-el-with-action">
        <span> This is some content I want portalled to the body </span>
    </div>
</body>

The desired result looks like this:

<body>
    <span> This is some content I want portalled to the body </span>
</body>

2. Doesn't play well with conditionals

Using the previous <Portal> example, if we had a few levels of components just forwarding props down/setting up context, etc. and there is a conditional at the grandchild level, you have a rogue "portal container" with nothing inside of it inside the portal target, which can have unexpected styling effects, etc.

Competitive Analysis

The other major web frameworks have first-party support for this:

Describe the proposed solution

Add a <Portal> component to Svelte.


type PortalProps = {
    /**
    * Where the children will be portalled to. Can either be a selector or an Element.
    * 
    * @defaultValue document.body 
    */
    target?: string | Element;

    /**
    * Whether portalling is disabled or not. When disabled, the children will
    * be rendered in their normal DOM order.
    * 
    * @defaultValue false
    */
    disabled: boolean;
}

### Importance

nice to have
brunnerh commented 1 week ago
huntabyte commented 1 week ago

Noticed there is an issue for this already so will close - #7082