Сниппеты и 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-пропсы.

Проверьте себя
1. Как называется проп, в который попадает контент между тегами компонента?
Aslot
Bcontent
Cchildren
Dinner
2. Что пришло на смену слотам (<slot>) в Svelte 5?
AПорталы
BСниппеты
CФрагменты React
DДирективы