Svelte: Portal in examples section

Created on 9 Jan 2020  路  11Comments  路  Source: sveltejs/svelte

Can we add this Portal repl in the examples section?

https://github.com/sveltejs/svelte/issues/3088#issuecomment-505785516

<script>
// src/components/Portal.svelte
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>

Copyright @ThomasJuster.

examples

Most helpful comment

You don't need the onDestroy. Svelte removes the element anyway.
You can event do it like that:

<script>
    let ref;
    $: ref && document.body.appendChild(ref);
</script>

<div class="portal" bind:this={ref}>
    <slot></slot>
</div>

All 11 comments

Could be a bit simpler

<script>
    import { onMount } from 'svelte';

    let ref;
    onMount(() => document.body.appendChild(ref));
</script>

<div class="portal" bind:this={ref}>
    <slot></slot>
</div>

@PatrickG, You forgot onDestroy().

You don't need the onDestroy. Svelte removes the element anyway.
You can event do it like that:

<script>
    let ref;
    $: ref && document.body.appendChild(ref);
</script>

<div class="portal" bind:this={ref}>
    <slot></slot>
</div>

Ok. And what If I need to "append" it not on body but in another component?

For example in <Sidebar /> already in App.svelte?

I'm using the id with document.getElementById("sidebar") right now but I'm wondering if there is a better way.

And sometimes (based on routing or custom logic, maybe behind a Svelte if false) the sidebar div is not present on the page, so it's a problem.

I opened this issue to address this "situation" "the right way".

Your hint?

That's not the right place to ask this kind of questions, you should discuss this on discord.
You could do something like this

<script>
  // App.svelte
  import Whatever from './Whatever.svelte';
  import Sidebar from './Sidebar.svelte';
</script>

<Sidebar Child={Whatever} />
<script>
  // Sidebar.svelte
  export Child = undefined;
</script>

{#if Child}
  <Child />
{/if}

@PatrickG this is not what I'm asking, but it's ok.

Talking about the onDestroy question, see here: https://github.com/romkor/svelte-portal/blob/master/src/Portal.svelte#L16-L18.

The guy here is using the onDestroy.

Is it wrong?

It's not wrong, just another way.

There's a typo in your code, a double ) in ...appendChild(ref));.

Can you explain it better the magic of this line?

$: ref && document.body.appendChild(ref);

I can open a PR for this example with your amazing code.

$: means it's a reactive statement.
As soon as the value of ref changes, it gets executed.
ref && ... is the same as if (ref) { ... }

You better ask such questions on discord.

<script>
  let ref;
  $: ref && document.body.appendChild(ref);
</script>

<div class="portal" bind:this={ref}>
  <slot></slot>
</div>

This should absolutely be in the svelte examples.

https://svelte.dev/repl/48afb902e70a4349bd0bfbe69d514df1?version=3.17.2 here is a repl

Was this page helpful?
0 / 5 - 0 ratings

Related issues

davidcallanan picture davidcallanan  路  3Comments

st-schneider picture st-schneider  路  3Comments

1u0n picture 1u0n  路  3Comments

thoughtspile picture thoughtspile  路  3Comments

mmjmanders picture mmjmanders  路  3Comments