Implement a portal in Svelte

Viewed 1927

In React you can render a component in a different node using Portals:

ReactDOM.createPortal( 
  <Component />,
  document.getElementById('id')
);

Same for Vue using the portal-vue package.

But is there a way to something similar in Svelte?

<body>
  <Header>
    <Modal /> <!-- Modal is rendered here -->
  </Header>

<!-- But the Modal DOM would be injected at the body end -->
</body>
2 Answers

See this issue : https://github.com/sveltejs/svelte/issues/3088

Portal.svelte

<script>
import { onMount, onDestroy } from 'svelte'
let ref
let portal

onMount(() => {
  portal = document.createElement('div')
  portal.className = 'portal'
  document.body.appendChild(portal)
  portal.appendChild(ref)
})

onDestroy(() => {
  document.body.removeChild(portal)
})

</script>

<div class="portal-clone">
  <div bind:this={ref}>
    <slot></slot>
  </div>
</div>
<style>
  .portal-clone { display: none; }
</style>

You can then you it with the following template. Modal will be renderer under <body/> :

<Portal>
  <Modal/>
</Portal>

Another solution would be to use the svelte-portal library:

​<script​>​
  ​import​ ​Portal​ ​from​ ​'svelte-portal'​;​
​</​script​>​

​<​Portal​ ​target​="​body"​>​
    <Modal/>
</​Portal​>​
Related