Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/sveltejs/svelte/llms.txt

Use this file to discover all available pages before exploring further.

Snippets are Svelte 5’s way to create reusable chunks of markup and pass content between components. They replace the legacy <slot> syntax with a more powerful and flexible system.

Snippets: The Basics

Snippets let you define reusable markup chunks:
{#snippet figure(image)}
  <figure>
    <img src={image.src} alt={image.caption} />
    <figcaption>{image.caption}</figcaption>
  </figure>
{/snippet}

{#each images as image}
  {#if image.href}
    <a href={image.href}>
      {@render figure(image)}
    </a>
  {:else}
    {@render figure(image)}
  {/if}
{/each}
1
Declaring Snippets
2
Snippets can have parameters with default values:
3
{#snippet greeting(name = 'world')}
  <p>Hello {name}!</p>
{/snippet}

{@render greeting()}
{@render greeting('Alice')}
4
Rendering Snippets
5
Use the @render tag to render snippets:
6
{#snippet card(title, description)}
  <div class="card">
    <h2>{title}</h2>
    <p>{description}</p>
  </div>
{/snippet}

{@render card('Welcome', 'This is a card component')}
7
Snippet Scope
8
Snippets can reference values from outer scopes:
9
<script>
  let { message = "it's great to see you!" } = $props();
</script>

{#snippet hello(name)}
  <p>hello {name}! {message}!</p>
{/snippet}

{@render hello('alice')}
{@render hello('bob')}

Passing Snippets to Components

Explicit Snippet Props

Pass snippets as props to create flexible, composable components:
<!-- App.svelte -->
<script>
  import Table from './Table.svelte';
  
  const fruits = [
    { name: 'apples', qty: 5, price: 2 },
    { name: 'bananas', qty: 10, price: 1 },
    { name: 'cherries', qty: 20, price: 0.5 }
  ];
</script>

{#snippet header()}
  <th>fruit</th>
  <th>qty</th>
  <th>price</th>
  <th>total</th>
{/snippet}

{#snippet row(d)}
  <td>{d.name}</td>
  <td>{d.qty}</td>
  <td>{d.price}</td>
  <td>{d.qty * d.price}</td>
{/snippet}

<Table data={fruits} {header} {row} />
<!-- Table.svelte -->
<script>
  let { data, header, row } = $props();
</script>

<table>
  <thead>
    <tr>{@render header()}</tr>
  </thead>
  <tbody>
    {#each data as item}
      <tr>{@render row(item)}</tr>
    {/each}
  </tbody>
</table>

Implicit Snippet Props

Snippets declared inside component tags automatically become props:
<!-- Semantically the same as above -->
<Table data={fruits}>
  {#snippet header()}
    <th>fruit</th>
    <th>qty</th>
    <th>price</th>
    <th>total</th>
  {/snippet}
  
  {#snippet row(d)}
    <td>{d.name}</td>
    <td>{d.qty}</td>
    <td>{d.price}</td>
    <td>{d.qty * d.price}</td>
  {/snippet}
</Table>

The Children Snippet

Content that’s not in a named snippet becomes the children snippet:
<!-- App.svelte -->
<script>
  import Button from './Button.svelte';
</script>

<Button>click me</Button>
<!-- Button.svelte -->
<script>
  let { children } = $props();
</script>

<button>{@render children()}</button>
This is the equivalent of Svelte 4’s default slot.

Optional Snippets

Make snippets optional with optional chaining or conditional rendering:
<script>
  let { children, header } = $props();
</script>

<!-- Optional chaining -->
{@render header?.()}

<!-- Or with fallback content -->
{#if children}
  {@render children()}
{:else}
  <p>No content provided</p>
{/if}

Typing Snippets

Use the Snippet interface from svelte for type safety:
<script lang="ts">
  import type { Snippet } from 'svelte';
  
  interface Props {
    data: any[];
    children?: Snippet;
    row: Snippet<[any]>;
    header?: Snippet;
  }
  
  let { data, children, row, header }: Props = $props();
</script>
The type argument is a tuple representing snippet parameters:
interface Props {
  simple: Snippet;              // No parameters
  withParam: Snippet<[string]>; // One parameter
  multiple: Snippet<[string, number]>; // Multiple parameters
}

Generic Snippet Types

Create type-safe snippets with generics:
<script lang="ts" generics="T">
  import type { Snippet } from 'svelte';
  
  let {
    data,
    children,
    row
  }: {
    data: T[];
    children?: Snippet;
    row: Snippet<[T]>;
  } = $props();
</script>

<div class="table">
  {#if children}
    {@render children()}
  {/if}
  
  {#each data as item}
    {@render row(item)}
  {/each}
</div>

Snippet Patterns

Render Props Pattern

Pass data from parent to snippet parameters:
<!-- DataProvider.svelte -->
<script>
  import type { Snippet } from 'svelte';
  
  let { children }: { children: Snippet<[{ user: User, posts: Post[] }]> } = $props();
  
  let data = $state({ user: null, posts: [] });
  
  onMount(async () => {
    data.user = await fetchUser();
    data.posts = await fetchPosts();
  });
</script>

{#if data.user}
  {@render children(data)}
{:else}
  <p>Loading...</p>
{/if}
<!-- App.svelte -->
<DataProvider>
  {#snippet children({ user, posts })}
    <h1>{user.name}</h1>
    <ul>
      {#each posts as post}
        <li>{post.title}</li>
      {/each}
    </ul>
  {/snippet}
</DataProvider>

Recursive Snippets

Snippets can reference themselves:
{#snippet countdown(n)}
  {#if n > 0}
    <span>{n}...</span>
    {@render countdown(n - 1)}
  {:else}
    <span>🚀</span>
  {/if}
{/snippet}

{@render countdown(10)}

Conditional Rendering

Provide different snippet implementations:
<script>
  import Card from './Card.svelte';
  
  let showImage = $state(true);
</script>

<Card>
  {#snippet header()}
    <h2>Product Details</h2>
  {/snippet}
  
  {#snippet body()}
    {#if showImage}
      <img src="product.jpg" alt="Product" />
    {/if}
    <p>Description goes here</p>
  {/snippet}
  
  {#snippet footer()}
    <button>Buy Now</button>
  {/snippet}
</Card>

Exporting Snippets

Snippets can be exported from <script module>:
<!-- snippets.svelte -->
<script module>
  export { add };
</script>

{#snippet add(a, b)}
  {a} + {b} = {a + b}
{/snippet}
<!-- App.svelte -->
<script>
  import { add } from './snippets.svelte';
</script>

{@render add(2, 3)}

Programmatic Snippets

Create snippets programmatically with createRawSnippet:
<script>
  import { createRawSnippet } from 'svelte';
  
  const dynamicSnippet = createRawSnippet((name) => {
    return {
      render: () => `<p>Hello ${name}!</p>`,
      setup: (element) => {
        // Optional setup logic
      }
    };
  });
</script>

{@render dynamicSnippet('World')}

Legacy Slots (Svelte 4)

In Svelte 4, content was passed using <slot> elements. This is now deprecated:
<!-- OLD: Svelte 4 -->
<!-- Modal.svelte -->
<div class="modal">
  <slot></slot>
  <hr>
  <slot name="buttons"></slot>
</div>
<!-- App.svelte -->
<Modal>
  This is slotted content
  
  <div slot="buttons">
    <button>Close</button>
  </div>
</Modal>
<!-- NEW: Svelte 5 -->
<!-- Modal.svelte -->
<script>
  let { children, buttons } = $props();
</script>

<div class="modal">
  {@render children?.()}
  <hr>
  {@render buttons?.()}
</div>
<!-- App.svelte -->
<Modal>
  This is slotted content
  
  {#snippet buttons()}
    <button>Close</button>
  {/snippet}
</Modal>

Best Practices

  1. Name snippets clearly - Use descriptive names that indicate what the snippet renders
  2. Document parameters - Make it clear what data snippets expect
  3. Provide fallbacks - Use optional chaining or conditional rendering for optional snippets
  4. Type your snippets - Use TypeScript for better autocomplete and error checking
  5. Keep snippets focused - Each snippet should have a single, clear purpose
<script lang="ts">
  import type { Snippet } from 'svelte';
  
  interface Props {
    /** Snippet for rendering the card header */
    header?: Snippet;
    /** Snippet for rendering the card body with access to data */
    body: Snippet<[{ title: string, description: string }]>;
    /** Snippet for rendering the card footer */
    footer?: Snippet;
  }
  
  let { header, body, footer }: Props = $props();
</script>