Svelte • Template syntax

{#snippet ...}

On this page
{#snippet const name: () => ReturnType<import("svelte").Snippet>name()}...{/snippet}
{#snippet name(param1, param2, paramN)}...{/snippet}

Snippets, and render tags, are a way to create reusable chunks of markup inside your components. Instead of writing duplicative code like this

{#each images as image}
	{#if image.href}
		<a href={image.href}>
			<figure>
				<img src={image.src} alt={image.caption} width={image.width} height={image.height} />
				<figcaption>{image.caption}</figcaption>
			</figure>
		</a>
	{:else}
		<figure>
			<img src={image.src} alt={image.caption} width={image.width} height={image.height} />
			<figcaption>{image.caption}</figcaption>
		</figure>
	{/if}
{/each}

…you can write this:

{#snippet figure(image)}
	<figure>
		<img src={image.src} alt={image.caption} width={image.width} height={image.height} />
		<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}

Like function declarations, snippets can have an arbitrary number of parameters, which can have default values, and you can destructure each parameter. You cannot use rest parameters, however.

Snippet scope

Snippets can be declared anywhere inside your component. They can reference values declared outside themselves, for example in the <script> tag or in {#each ...} blocks…

<script lang="ts">
	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')}
<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')}

…and they are ‘visible’ to everything in the same lexical scope (i.e. siblings, and children of those siblings):

<div>
	{#snippet x()}
		{#snippet y()}...{/snippet}

		<!-- this is fine -->
		{@render y()}
	{/snippet}

	<!-- this will error, as `y` is not in scope -->
	{@render y()}
</div>

<!-- this will also error, as `x` is not in scope -->
{@render x()}

Snippets can reference themselves and each other:

{#snippet blastoff()}
	<span>🚀</span>
{/snippet}

{#snippet countdown(n)}
	{#if n > 0}
		<span>{n}...</span>
		{@render countdown(n - 1)}
	{:else}
		{@render blastoff()}
	{/if}
{/snippet}

{@render countdown(10)}

Passing snippets to components

Explicit props

Within the template, snippets are values just like any other. As such, they can be passed to components as props:

<script lang="ts">
	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} />
<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} />
<script lang="ts">
	let { let data: anydata, let header: anyheader, let row: anyrow } = 
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script> <table> {#if let header: anyheader} <thead> <tr>{@render let header: anyheader()}</tr> </thead> {/if} <tbody> {#each let data: anydata as let d: anyd} <tr>{@render let row: anyrow(let d: anyd)}</tr> {/each} </tbody> </table> <style> table { text-align: left; border-spacing: 0; } tbody tr:nth-child(2n+1) { background: ButtonFace; } table :global(th), table :global(td) { padding: 0.5em; } </style>
<script>
	let { let data: anydata, let header: anyheader, let row: anyrow } = 
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script> <table> {#if let header: anyheader} <thead> <tr>{@render let header: anyheader()}</tr> </thead> {/if} <tbody> {#each let data: anydata as let d: anyd} <tr>{@render let row: anyrow(let d: anyd)}</tr> {/each} </tbody> </table> <style> table { text-align: left; border-spacing: 0; } tbody tr:nth-child(2n+1) { background: ButtonFace; } table :global(th), table :global(td) { padding: 0.5em; } </style>

Think about it like passing content instead of data to a component. The concept is similar to slots in web components.

Implicit props

As an authoring convenience, snippets declared directly inside a component implicitly become props on the component:

<script lang="ts">
	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>

<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>
<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>

<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>
<script lang="ts">
	let { let data: anydata, let header: anyheader, let row: anyrow } = 
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script> <table> {#if let header: anyheader} <thead> <tr>{@render let header: anyheader()}</tr> </thead> {/if} <tbody> {#each let data: anydata as let d: anyd} <tr>{@render let row: anyrow(let d: anyd)}</tr> {/each} </tbody> </table> <style> table { text-align: left; border-spacing: 0; } tbody tr:nth-child(2n+1) { background: ButtonFace; } table :global(th), table :global(td) { padding: 0.5em; } </style>
<script>
	let { let data: anydata, let header: anyheader, let row: anyrow } = 
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script> <table> {#if let header: anyheader} <thead> <tr>{@render let header: anyheader()}</tr> </thead> {/if} <tbody> {#each let data: anydata as let d: anyd} <tr>{@render let row: anyrow(let d: anyd)}</tr> {/each} </tbody> </table> <style> table { text-align: left; border-spacing: 0; } tbody tr:nth-child(2n+1) { background: ButtonFace; } table :global(th), table :global(td) { padding: 0.5em; } </style>

Implicit children snippet

Any content inside the component tags that is not a snippet declaration implicitly becomes part of the children snippet:

<script lang="ts">
	import 
type Button = SvelteComponent<Record<string, any>, any, any>
const Button: LegacyComponentType
Button
from './Button.svelte';
</script> <const Button: LegacyComponentTypeButton>click me</Button>
<script>
	import 
type Button = SvelteComponent<Record<string, any>, any, any>
const Button: LegacyComponentType
Button
from './Button.svelte';
</script> <const Button: LegacyComponentTypeButton>click me</Button>
<script lang="ts">
	let { let children: anychildren } = 
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script> <!-- result will be <button>click me</button> --> <button>{@render let children: anychildren()}</button>
<script>
	let { let children: anychildren } = 
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script> <!-- result will be <button>click me</button> --> <button>{@render let children: anychildren()}</button>

Note that you cannot have a prop called children if you also have content inside the component — for this reason, you should avoid having props with that name

Optional snippet props

You can declare snippet props as being optional. You can either use optional chaining to not render anything if the snippet isn’t set…

<script lang="ts">
    let { let children: anychildren } = 
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script> {@render let children: anychildren?.()}
<script>
    let { let children: anychildren } = 
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script> {@render let children: anychildren?.()}

…or use an #if block to render fallback content:

<script lang="ts">
    let { let children: anychildren } = 
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script> {#if let children: anychildren} {@render let children: anychildren()} {:else} fallback content {/if}
<script>
    let { let children: anychildren } = 
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script> {#if let children: anychildren} {@render let children: anychildren()} {:else} fallback content {/if}

Typing snippets

Snippets implement the Snippet interface imported from 'svelte':

<script lang="ts">
	import type { interface Snippet<Parameters extends unknown[] = []>

The type of a #snippet block. You can use it to (for example) express that your component expects a snippet of a certain type:

let { banner }: { banner: Snippet<[{ text: string }]> } = $props();

You can only call a snippet through the {@render ...} tag.

See the snippet documentation for more info.

@templateParameters the parameters that the snippet expects (if any) as a tuple.
Snippet
} from 'svelte';
interface Props { Props.data: any[]data: any[]; Props.children: Snippet<[]>children: interface Snippet<Parameters extends unknown[] = []>

The type of a #snippet block. You can use it to (for example) express that your component expects a snippet of a certain type:

let { banner }: { banner: Snippet<[{ text: string }]> } = $props();

You can only call a snippet through the {@render ...} tag.

See the snippet documentation for more info.

@templateParameters the parameters that the snippet expects (if any) as a tuple.
Snippet
;
Props.row: Snippet<[any]>row: interface Snippet<Parameters extends unknown[] = []>

The type of a #snippet block. You can use it to (for example) express that your component expects a snippet of a certain type:

let { banner }: { banner: Snippet<[{ text: string }]> } = $props();

You can only call a snippet through the {@render ...} tag.

See the snippet documentation for more info.

@templateParameters the parameters that the snippet expects (if any) as a tuple.
Snippet
<[any]>;
} let { let data: any[]data, let children: Snippet<[]>children, let row: Snippet<[any]>row }: Props =
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script>

With this change, red squigglies will appear if you try and use the component without providing a data prop and a row snippet. Notice that the type argument provided to Snippet is a tuple, since snippets can have multiple parameters.

We can tighten things up further by declaring a generic, so that data and row refer to the same type:

<script lang="ts" generics="
function (type parameter) T in $$render<T>(): {
    props: $$ComponentProps;
    exports: {};
    bindings: "";
    slots: {};
    events: {};
}
T
">
import type { interface Snippet<Parameters extends unknown[] = []>

The type of a #snippet block. You can use it to (for example) express that your component expects a snippet of a certain type:

let { banner }: { banner: Snippet<[{ text: string }]> } = $props();

You can only call a snippet through the {@render ...} tag.

See the snippet documentation for more info.

@templateParameters the parameters that the snippet expects (if any) as a tuple.
Snippet
} from 'svelte';
let { let data: T[]data, let children: Snippet<[]>children, let row: Snippet<[T]>row }: { data: T[]data:
function (type parameter) T in $$render<T>(): {
    props: $$ComponentProps;
    exports: {};
    bindings: "";
    slots: {};
    events: {};
}
T
[];
children: Snippet<[]>children: interface Snippet<Parameters extends unknown[] = []>

The type of a #snippet block. You can use it to (for example) express that your component expects a snippet of a certain type:

let { banner }: { banner: Snippet<[{ text: string }]> } = $props();

You can only call a snippet through the {@render ...} tag.

See the snippet documentation for more info.

@templateParameters the parameters that the snippet expects (if any) as a tuple.
Snippet
;
row: Snippet<[T]>row: interface Snippet<Parameters extends unknown[] = []>

The type of a #snippet block. You can use it to (for example) express that your component expects a snippet of a certain type:

let { banner }: { banner: Snippet<[{ text: string }]> } = $props();

You can only call a snippet through the {@render ...} tag.

See the snippet documentation for more info.

@templateParameters the parameters that the snippet expects (if any) as a tuple.
Snippet
<[
function (type parameter) T in $$render<T>(): {
    props: $$ComponentProps;
    exports: {};
    bindings: "";
    slots: {};
    events: {};
}
T
]>;
} =
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
$
function $props(): any
namespace $props

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
@see{@link https://svelte.dev/docs/svelte/$props Documentation}
props
();
</script>

Exporting snippets

Snippets declared at the top level of a .svelte file can be exported from a <script module> for use in other components, provided they don’t reference any declarations in a non-module <script> (whether directly or indirectly, via other snippets):

<script lang="ts">
	import { add } from './snippets.svelte';
</script>

{@render add(1, 2)}
<script>
	import { add } from './snippets.svelte';
</script>

{@render add(1, 2)}
<script lang="ts" module>
	export { add };
</script>

{#snippet add(a, b)}
	{a} + {b} = {a + b}
{/snippet}
<script module>
	export { add };
</script>

{#snippet add(a, b)}
	{a} + {b} = {a + b}
{/snippet}

This requires Svelte 5.5.0 or newer

Programmatic snippets

Snippets can be created programmatically with the createRawSnippet API. This is intended for advanced use cases.

Snippets and slots

In Svelte 4, content can be passed to components using slots. Snippets are more powerful and flexible, and so slots have been deprecated in Svelte 5.