How to mount HTMLElement directly in Svelte?

Viewed 425

I'm using some external code that returns an HTML element, and it'd be nice to embed it without having to manage the loading and everything via JavaScript (i.e. appendChild/removeChild). Right now I'm using {@html element.outerHTML}, but this seems inelegant to make the round trip to an HTML string:

<script>
  function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  async function someCall() {
    await sleep(1000);
    const p = document.createElement("p");
    p.innerText = "hello!";
    console.log(p);
    return p;
  }

  let data = someCall();
</script>

<div>
  {#await data}
    <p>Loading data...</p>
  {:then result}
    {@html result.outerHTML}
  {/await}
</div>

What I'm looking for might be something like

<div>
  {#await data}
    <p>Loading data...</p>
  {:then result}
    {result}
  {/await}
</div>

but this doesn't work (since it string-ifies the element).

2 Answers

I think you can do it like this.

<script>
  function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  async function someCall() {
    await sleep(1000);
    return `<p>hello</p>`;
  }

  let data = someCall();
</script>

<main>
    <div>
  {#await data}
    <p>Loading data...</p>
  {:then result}
    {@html result}
  {/await}
</div>
</main>

https://codesandbox.io/s/blissful-sea-mfcx5?file=/App.svelte:0-336

You can use bind:this to append HTML

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

    function sleep(ms) {
      return new Promise((resolve) => setTimeout(resolve, ms));
    }

    let elem;
    
    onMount(async () => {
      await sleep(1000);
      const p = document.createElement("p");
      p.innerText = "hello!";
      elem.appendChild(p) 
    });
</script>

<div bind:this={elem}> 
</div>
Related