Skip to content

Better docs for snippets-slots interopΒ #13867

@rChaoz

Description

@rChaoz

Describe the bug

In the docs, the only mention of snippets-slots interop is:

In Svelte 4, content can be passed to components using slots. Svelte 5 replaces them with snippets which are more powerful and flexible, and as such slots are deprecated in Svelte 5.

They continue to work, however, and you can mix and match snippets and slots in your components.

But it doesn't say exactly what that means. It is intuitive that you can use old components with slots from new snippet-based components, but not the other way around, and that slot props are passed using destructuring, as they are named, but I think this should be documented a bit.

For example:

<!-- Child.svelte -->
<slot name="named" />
<br>
<slot />


<!-- Parent.svelte -->
<Child>
  {#snippet named()}
    Named
  {/snippet}
  Default
</Child>

And with values:

<!-- Child.svelte -->
<script>
  let value = 0
</script>

<slot name="named" {value} />
<br>
<slot {value} />
<br>
<button on:click={() => value++}>Increment</button>


<!-- Parent.svelte -->
<Child>
  {#snippet named({ value })}
    Named: {value}
  {/snippet}
  {#snippet children({ value })}
    Default with value: {value}
  {/snippet}
</Child>

But the other way around doesn't work (except for default slots and without props), as it doesn't make sense to write Svelte 4 code using Svelte 5 code, but I think it can happen if upgrading to Svelte 5 libraries in a codebase that's not fully migrated:

<!-- Child.svelte -->
<script>
  let { children, named } = $props()
</script>

{@render children?.()}
<br>
{@render named?.()}


<!-- Parent.svelte -->
<Child>
  <!-- This doesn't get rendered -->
  <svelte:fragment slot="named">
    Named
  </svelte:fragment>
  Default
</Child>

Or:

<!-- Child.svelte -->
<script>
  let { children, named } = $props()
</script>

{@render children?.({ value: 123 })}


<!-- Parent.svelte -->
<!-- invalid_default_snippet Cannot use `{@render children(...)}` if the parent component uses `let:` directives. Consider using a named snippet instead in New.svelte in App.svelte  -->
<Child let:value>
  Value: {value}
</Child>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions