sveltesvelte-5flowbite-svelte

Declare a snippet inside a component without it being implicitly passed to the component as a prop


The Svelte tutorial demonstrates how to declare a table row snippet:

<tbody>
    {#snippet monkey()}...{/snippet}

    {@render monkey()}
</tbody>

So far so good. Makes sense to put a snippet close to where it is being used - a table row snippet indeed belongs in tbody.

I also want to reuse a table row snippet. Except I use the Flowbite Svelte component library. So the code looks like this:

<Table>
    ...
    <TableBody>
        {#snippet row(row: UserProductListEntry)}
            {row.product.title}
        {/snippet}

This works at runtime, but it has issues due to the snippet implicitly becoming TableBody's prop:

  1. I'm getting this type error: IDE Error Is this an IDEA Svelte plugin's error? It doesn't have any references e.g. to ESLint. Should it be a warning and/or suppressible? I haven't found anything like this at the JetBrains's issue tracker.
  2. (Less important) In this case I don't intend to pass the snippet to TableBody as a prop. What if it just so happens to expect a snippet by the same name?

So the question is, is there a way to opt out this snippet from becoming an implicit prop? Or at least deal with issue 1 somehow, without moving the snippet out of the TableBody and Table?


Solution

  • The error is a bit of a false positive and is triggered by passing a snippet to a component that uses slots rather than snippets & @render. (I reported this already.)

    Snippet to slot interop only works if snippets are passed as props that share the name of the slot.

    In cases where you only want a local snippet, you could explicitly declare the default slot/snippet. So for a Svelte 5 which uses a children snippet that usually can be omitted:

    <Component>
      {#snippet children()}
        {#snippet localSnippet()} ... {/snippet}
    
        {@render localSnippet()}
      {/snippet}
    </Component>
    

    For legacy components like currently those of Flowbite, you probably need a default slot element/fragment instead.

    To avoid the error, for now you could use <slot> syntax like this:

    <TableBody>
      <svelte:fragment slot="row" let:item={row} >
        {row.product.title}
      </svelte:fragment>
    

    (This code would use the row slot as intended; the component already loops over all rows, so you only have to define a row snippet or slot to render everything.)