Сниппеты и children вместо слотов
Сниппеты — это переиспользуемые куски разметки. Содержимое между тегами компонента приходит как children.
Сниппеты пришли на смену слотам и оказались мощнее: это разметка, которую можно передавать как значение и вызывать с параметрами.
Часто компонент-обёртка должен показать произвольное содержимое внутри себя: модальное окно, карточку, layout. В Svelte 5 для этого служат сниппеты. Содержимое, которое вы кладёте между открывающим и закрывающим тегами компонента, автоматически становится сниппетом-пропсом с именем children. Внутри компонента вы выводите его директивой {@render children()}.
Сниппеты заменили слоты из Svelte 4 и сделали систему гибче. Сниппет — это не просто «дырка для контента», а полноценный переиспользуемый фрагмент разметки, который можно объявить, передать как значение и даже вызвать с аргументами. Но базовый случай прост: оберните содержимое и отрендерьте его.
<!-- Card.svelte -->
<script>
let { children } = $props();
</script>
<div class="card">
{@render children()}
</div>Родитель просто кладёт контент внутрь тегов:
<!-- родитель -->
<Card>
<h3>Заголовок</h3>
<p>Любая разметка попадёт в карточку.</p>
</Card>Можно объявлять и именованные сниппеты с параметрами через блок {#snippet name(arg)} и рендерить их через {@render name(value)}. Это позволяет, например, передавать в список способ отрисовки каждого элемента — аналог render-пропсов из React, но удобнее.
<!-- список с пользовательской отрисовкой строки -->
<script>
let { items, row } = $props();
</script>
<ul>
{#each items as item}
<li>{@render row(item)}</li>
{/each}
</ul>Как это работает под капотом
Сниппет — это функция, возвращающая разметку. «Отрендерить сниппет» значит вызвать эту функцию в нужном месте. Смоделируем идею на JS: контент как функция, которую обёртка вызывает внутри себя.
// Сниппет — это функция, возвращающая разметку
function Card({ children }) {
return `<div class="card">${children()}</div>`; // вызываем сниппет
}
// именованный сниппет с параметром
const row = (item) => `<b>${item.name}</b>: ${item.score}`;
function List({ items, row }) {
return '<ul>' + items.map(i => `<li>${row(i)}</li>`).join('') + '</ul>';
}
console.log(Card({ children: () => '<p>Привет</p>' }));
console.log(List({ items: [{name:'Аня',score:9},{name:'Борис',score:7}], row }));Попробуй сам ▶ — вставь код в консоль браузера (F12 → Console) и нажми Enter, чтобы увидеть вывод.
<Card> ...контент... </Card>
|
v
children (сниппет-функция)
|
v
{@render children()} внутри Card -> вставка разметкиЧастые ошибки
- Искать слоты
<slot>в Svelte 5. Они устарели; используйтеchildrenи сниппеты. - Забыть
{@render children()}. Без него переданный контент просто не появится. - Не передавать параметры именованным сниппетам, когда они их ожидают.
Best practices
- Используйте
childrenдля простого вложенного контента — это самый частый случай. - Применяйте именованные сниппеты с параметрами для гибкой отрисовки списков и таблиц.
- Воспринимайте сниппет как функцию-разметку: его можно передавать и вызывать.
Сниппеты как способ инвертировать управление
За скромным синтаксисом сниппетов скрывается мощная идея — инверсия управления отрисовкой. Обычно родитель передаёт данные, а ребёнок решает, как их показать. Со сниппетами родитель может передать ребёнку и сам способ отрисовки, оставив за дочерним компонентом только логику обхода и компоновки. Классический пример — универсальный компонент таблицы или списка: он умеет получать данные, фильтровать, сортировать и пагинировать, но не диктует, как выглядит отдельная строка. Способ отрисовки строки приходит снаружи в виде именованного сниппета с параметром. В результате один компонент таблицы переиспользуется для пользователей, товаров и заказов, хотя строки в этих случаях выглядят совершенно по-разному. Это тот же приём, что в React называют render-пропсами, но в Svelte он встроен в язык и читается естественнее. Освоив сниппеты, вы научитесь строить по-настоящему гибкие переиспользуемые компоненты.
Итог: сниппеты — переиспользуемые фрагменты разметки. Вложенный контент приходит как children и выводится через {@render}; именованные сниппеты с параметрами заменяют render-пропсы.