Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I return the rendered HTML of a Svelte component?

I'm having a tough time making a tooltip that runs off use:action. My requirements are:

  1. Create a tooltip with HTML or a Component as the content
  2. Without having to wrap a component in a <Tooltip><element></Tooltip>
  3. Hook in to premade libraries for flexibility

Please see my example code below. It doesn't work in the REPL due to Tippy.js dependencies, but I do have it working with simple HTML in my app. This is why my thinking is that I should seek to render a component, which acknowledges props like any other, then somehow take its HTML and put it in use:action call. (see "content: 'Hey I work!'") It should be as simple to use as in the days of jQuery's tooltips.

REPL link: https://svelte.dev/repl/e8fdf98eb42445e3b791d7c908581a71?version=3.17.3

like image 377
Vael Victus Avatar asked Jan 25 '23 09:01

Vael Victus


1 Answers

To really "return the rendered HTML", you'd need to compile with generate: 'ssr' option, and use the Cmp.render() function. But you cannot use such a component in the DOM...

You can't really get the content of a component, but you can get the HTML of any element using an action like such:

<script>
const logHtml = el => {
  console.log(el.innerHTML)
}
</script>

<div use:logHtml> ... </div>

Or, simply, bind:this on elements:

<script>
  let el
  $: if (el) console.log(el.innerHTML)
</script>

<div bind:this={el}> ... </div>

In your case, though, it seems that what you want is to render the component directly into the tooltip's element. You can use new MyComponent for that.

Here's an example action rendering a custom component with tippy.js (see updated REPL):

export function tipz(elem, { content, props, ...opts }) {
  let cmp

  const tp = tippy(elem, {
    onCreate() {
      cmp = new content({
        target: instance.popper.querySelector(".tippy-content"),
        props,
      });
    },
    ...opts
  })

  return {
    update(params) {
      // ensure reactivity
      if (cmp) {
        cmp.$set(params.props)
      }
    },
    destroy() {
      tp.destroy();
      if (cmp) {
        // cleanup component
        cmp.$destroy();
      }
    }
  };
}
like image 133
rixo Avatar answered Mar 15 '23 04:03

rixo