06 - Snippets

What are Snippets?

Snippets replace slots for passing content to components. More flexible and explicit than the old slot system.

Svelte 4 (Legacy — Slots)

<!-- Child.svelte -->
<div class="card">
  <slot name="header" />
  <slot />
  <slot name="footer" />
</div>
<!-- Parent.svelte -->
<Card>
  <h1 slot="header">Title</h1>
  <p>Default content</p>
  <p slot="footer">Footer</p>
</Card>

Svelte 5 (Snippets)

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

<div class="card">
  {@render header()}
  {@render children()}
  {@render footer()}
</div>
<!-- Parent.svelte -->
<Card>
  {#snippet header()}
    <h1>Title</h1>
  {/snippet}
  
  <p>Default content</p>
  
  {#snippet footer()}
    <p>Footer</p>
  {/snippet}
</Card>

The key difference: snippets are just props (functions that return markup), so they're explicit, typed, and can accept parameters. children is a special snippet that captures any content not inside a named {#snippet}.

Basic Usage

children is the default snippet — it captures any content placed directly inside the component tags (not inside a named {#snippet}).

Child Component:

<!-- src/lib/components/Card.svelte -->
<script>
let { children } = $props();
</script>

<div class="card">
  {@render children()}
</div>

Parent:

<!-- src/routes/+page.svelte -->
<script>
import Card from '$lib/components/Card.svelte';
</script>

<Card>
  <p>This is the content</p>  <!-- becomes "children" -->
</Card>

Named Snippets

Named snippets let you pass multiple blocks of content to specific locations in a child component.

Child:

<!-- src/lib/components/Card.svelte -->
<script>
let { header, footer } = $props();
</script>

<div class="card">
  {@render header()}
  <main>Main content</main>
  {@render footer()}
</div>

Parent:

<!-- src/routes/+page.svelte -->
<script>
import Card from '$lib/components/Card.svelte';
</script>

<Card>
  {#snippet header()}
    <h1>Title</h1>
  {/snippet}
  
  {#snippet footer()}
    <p>Footer text</p>
  {/snippet}
</Card>

Snippets with Parameters

Snippets can receive data from the child component — the child calls {@render row(item)} with arguments, and the parent's snippet receives them.

Child:

<!-- src/lib/components/List.svelte -->
<script>
let { row } = $props();
let items = [1, 2, 3];
</script>

{#each items as item}
  {@render row(item)}  <!-- passes item to the parent's snippet -->
{/each}

Parent:

<!-- src/routes/+page.svelte -->
<script>
import List from '$lib/components/List.svelte';
</script>

<List>
  {#snippet row(item)}
    <div>Item: {item}</div>  <!-- receives item from child -->
  {/snippet}
</List>

Local Snippets

Snippets don't have to be passed to components — you can define and render them locally as reusable markup templates within the same file.

{#snippet card(title, content)}
  <div class="card">
    <h2>{title}</h2>
    <p>{content}</p>
  </div>
{/snippet}

{@render card('Title 1', 'Content 1')}
{@render card('Title 2', 'Content 2')}

Key Points

  • Replaces Svelte 4's <slot> system
  • Snippets are props — explicit, typed, and can accept parameters
  • children captures default content (not inside a named {#snippet})
  • {#snippet name()} defines a snippet, {@render name()} renders it
  • Can be used locally as reusable markup templates or passed to child components

Interactive Example

<script>
import Card from './06-snippets-child.svelte';
import List from './06-snippets-list.svelte';

// Local snippet
{#snippet badge(text, color)}
  <span class="badge" style="background: {color}">
    {text}
  </span>
{/snippet}
</script>

<div>
  <h2>06 - Snippets Example</h2>
  
  <h3>Basic Snippets (Named)</h3>
  <Card>
    {#snippet header()}
      <h3>Card Title</h3>
    {/snippet}
    
    <p>This is the main content of the card.</p>
    
    {#snippet footer()}
      <small>Last updated: Today</small>
    {/snippet}
  </Card>
  
  <h3>Snippets with Parameters</h3>
  <List>
    {#snippet row(item)}
      <div class="row">
        <span>{item.name}</span>
        <span>${item.price}</span>
      </div>
    {/snippet}
  </List>
  
  <h3>Local Snippets</h3>
  <div>
    {@render badge('New', '#4CAF50')}
    {@render badge('Sale', '#FF5722')}
    {@render badge('Popular', '#2196F3')}
  </div>
</div>

<style>
div { margin: 20px; }
h3 { margin-top: 20px; }
.badge {
  display: inline-block;
  padding: 5px 10px;
  margin: 5px;
  color: white;
  border-radius: 3px;
  font-size: 0.9em;
}
:global(.row) {
  display: flex;
  justify-content: space-between;
  padding: 10px;
  border-bottom: 1px solid #eee;
}
</style>