Nested content and snippets
Sometimes a component needs not data but a whole piece of markup: a card with arbitrary content, a list where the parent decides what a row looks like. In Svelte 5 such a piece of markup is called a snippet, and it is rendered with the {@render} tag.
Content between the tags
Whatever the parent writes between a component's opening and closing tags arrives in the children prop. Create the file src/lib/components/Card.svelte:
<!-- src/lib/components/Card.svelte -->
<script>
let { children } = $props();
</script>
<section class="card">
{@render children()}
</section>
<style>
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
}
</style>The component draws a frame and renders whatever it was given inside.
Using it
<!-- src/routes/+page.svelte -->
<script>
import Card from '$lib/components/Card.svelte';
</script>
<Card>
<h2>My tasks</h2>
<p>Tasks for today: 3</p>
</Card>The page shows a frame with rounded corners containing the heading and the paragraph. One Card component fits any content.
When there is no content
If you write <Card /> with no content, children is undefined, and children() throws an error. For optional content, call it with ?.:
<!-- src/lib/components/Card.svelte -->
<script>
let { children } = $props();
</script>
<section class="card">
{@render children?.()}
</section>Your own snippet with a parameter
A snippet can also be declared by hand with a {#snippet name(params)} block. Declared inside a component's tag, it becomes a prop with the same name. Let us make a list where the parent decides what a row looks like:
<!-- src/lib/components/TodoList.svelte -->
<script>
let { todos, row } = $props();
</script>
<ul>
{#each todos as todo (todo.id)}
<li>{@render row(todo)}</li>
{/each}
</ul><!-- src/routes/+page.svelte -->
<script>
import TodoList from '$lib/components/TodoList.svelte';
let todos = $state([
{ id: 1, text: 'Buy bread', done: true },
{ id: 2, text: 'Call Oleg', done: false }
]);
</script>
<TodoList {todos}>
{#snippet row(todo)}
<strong>{todo.done ? '✓' : '○'}</strong> {todo.text}
{/snippet}
</TodoList>TodoList goes through the tasks and calls the row snippet for each, passing it the task. The look of the row is decided by the page: a bold mark and the text.
A snippet inside one component
A snippet declared in regular markup can be rendered several times in the same file — a way to avoid repeating the same piece of markup without creating a separate component.
Common mistake
Rendering a snippet with curly braces and no @render: {children} or {row(todo)}. A snippet is a special kind of function, not a string, so nothing useful appears on the page. Snippets are always rendered with the {@render ...} tag.