Вложенное содержимое и сниппеты
Иногда компоненту нужно передать не данные, а целый кусок разметки: карточка с произвольным содержимым, список, в котором родитель решает, как выглядит строка. В Svelte 5 такой кусок разметки называется сниппетом (snippet), а выводится он тегом {@render}.
Содержимое между тегами
Всё, что родитель пишет между открывающим и закрывающим тегом компонента, приходит в свойство children. Создайте файл 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>Компонент рисует рамку, а внутрь выводит то, что ему передали.
Использование
<!-- src/routes/+page.svelte -->
<script>
import Card from '$lib/components/Card.svelte';
</script>
<Card>
<h2>Мои задачи</h2>
<p>Задач на сегодня: 3</p>
</Card>На странице появится рамка со скруглёнными углами, а в ней заголовок и абзац. Один компонент Card подойдёт для любого содержимого.
Если содержимого нет
Если вызвать <Card /> без содержимого, children будет undefined, и children() вызовет ошибку. Для необязательного содержимого используйте вызов с ?.:
<!-- src/lib/components/Card.svelte -->
<script>
let { children } = $props();
</script>
<section class="card">
{@render children?.()}
</section>Свой сниппет с параметром
Сниппет можно объявить и вручную блоком {#snippet имя(параметры)}. Объявленный внутри тега компонента, он становится свойством с тем же именем. Сделаем список, в котором родитель решает, как выглядит строка:
<!-- 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: 'Купить хлеб', done: true },
{ id: 2, text: 'Позвонить Олегу', done: false }
]);
</script>
<TodoList {todos}>
{#snippet row(todo)}
<strong>{todo.done ? '✓' : '○'}</strong> {todo.text}
{/snippet}
</TodoList>TodoList перебирает задачи и для каждой вызывает сниппет row, передавая ему задачу. Вид строки при этом задаёт страница: жирная отметка и текст.
Сниппет внутри одного компонента
Сниппет, объявленный в обычной разметке, можно вызывать несколько раз в том же файле — это способ не повторять одинаковый кусок разметки без отдельного компонента.
Частая ошибка
Выводить сниппет фигурными скобками без @render: {children} или {row(todo)}. Сниппет — функция особого вида, а не строка, поэтому на странице ничего полезного не появится. Сниппеты всегда выводят тегом {@render ...}.