Что такое слоты и зачем они нужны?

В Vue слоты (slots) — это механизм для вставки пользовательского контента в шаблон компонента. Они позволяют создавать более гибкие и переиспользуемые компоненты, в которые можно передавать разную разметку или структуру из родительского компонента.

Слоты работают как замещаемые места в шаблоне, куда родительский компонент может вставить произвольный HTML или Vue-компоненты.

Простые (одиночные) слоты

Обычный слот создаётся с помощью <slot></slot>. Всё, что передаётся внутрь компонента между его тегами, будет вставлено в это место.

Пример: компонент BaseCard.vue

&lt;template&gt;
&lt;div class="card"&gt;
&lt;slot&gt;&lt;/slot&gt;
&lt;/div&gt;
&lt;/template&gt;

Использование:

&lt;BaseCard&gt;
&lt;p&gt;Привет, это содержимое карточки&lt;/p&gt;
&lt;/BaseCard&gt;

Результат: <p> вставится внутрь div.card.

Слот по умолчанию и запасное содержимое

Если родитель ничего не передал, можно отобразить содержимое по умолчанию:

&lt;template&gt;
&lt;div&gt;
&lt;slot&gt;Текст по умолчанию&lt;/slot&gt;
&lt;/div&gt;
&lt;/template&gt;

Именованные слоты

Когда компонент должен принимать несколько отдельных участков содержимого, используются именованные слоты.

Пример: компонент BaseLayout.vue

&lt;template&gt;
&lt;div class="layout"&gt;
&lt;header&gt;&lt;slot name="header" /&gt;&lt;/header&gt;
&lt;main&gt;&lt;slot /&gt;&lt;/main&gt;
&lt;footer&gt;&lt;slot name="footer" /&gt;&lt;/footer&gt;
&lt;/div&gt;
&lt;/template&gt;

Использование:

&lt;BaseLayout&gt;
&lt;template v-slot:header&gt;
&lt;h1&gt;Заголовок&lt;/h1&gt;
&lt;/template&gt;
&lt;p&gt;Основной контент страницы&lt;/p&gt;
&lt;template v-slot:footer&gt;
&lt;p&gt;Футер © 2025&lt;/p&gt;
&lt;/template&gt;
&lt;/BaseLayout&gt;

Если контент без v-slot — он идёт в дефолтный слот (<slot />), остальные — по имени.

Сокращённая запись v-slot

Можно использовать сокращение #имя:

&lt;template #header&gt;
&lt;h1&gt;Сокращённая запись&lt;/h1&gt;
&lt;/template&gt;

Для дефолтного слота: v-slot:default или #default.

Скопированные атрибуты в слотах (атрибут v-bind)

Vue позволяет передавать данные из дочернего компонента в слот с помощью scope slots (слоты с областью видимости). Это полезно, если компонент должен управлять частью данных, но внешний шаблон — управлять отображением.

Пример: компонент ItemList.vue

&lt;template&gt;
&lt;ul&gt;
&lt;li v-for="item in items" :key="item.id"&gt;
&lt;slot :item="item" /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/template&gt;
&lt;script&gt;
export default {
props: \['items'\]
}
&lt;/script&gt;

Использование с родительской стороны:

&lt;ItemList :items="products"&gt;
&lt;template v-slot:default="{ item }"&gt;
&lt;strong&gt;{{ item.name }}&lt;/strong&gt;: {{ item.price }}$
&lt;/template&gt;
&lt;/ItemList&gt;

В этом примере дочерний компонент управляет списком, но родитель управляет тем, как каждый элемент отрисовывается.

Пример для компонентов таблиц

Компонент таблицы может иметь слот для кастомного отображения ячеек:

&lt;Table :rows="users"&gt;
&lt;template v-slot:cell-name="{ row }"&gt
&lt;a :href="\`/user/${row.id}\`"&gt;{{ row.name }}&lt;/a&gt;
&lt;/template&gt;
&lt;/Table&gt;

А компонент Table.vue внутри будет вызывать слот:

&lt;td&gt;
&lt;slot name="cell-name" :row="user"&gt;{{ user.name }}&lt;/slot&gt;
&lt;/td&gt;

Совместное использование слотов и пропсов

Компоненты могут передавать данные через слот, чтобы родитель получил возможность на их основе построить шаблон. Это особенно важно, если данные внутри компонента, а внешний код должен их визуализировать.

Вложенные компоненты со слотами

Слоты поддерживаются и во вложенных структурах, но важно следить за тем, как они пробрасываются.

&lt;BaseLayout&gt;
&lt;template #header&gt;
&lt;MyNav /&gt;
&lt;/template&gt;
&lt;template #default&gt;
&lt;MainContent /&gt;
&lt;/template&gt;
&lt;/BaseLayout&gt;

BaseLayout может использовать слоты как контейнер, при этом весь контент определяется снаружи.

Динамические имена слотов

В обычной практике Vue не поддерживает динамически вычисляемые имена слотов, но с помощью v-if и v-slot можно управлять тем, какие слоты активны, на основе данных:

&lt;component :is="layout"&gt;
&lt;template v-slot:\[activeSlot\]&gt;
&lt;p&gt;Контент активного слота&lt;/p&gt;
&lt;/template&gt;
&lt;/component&gt;

Комбинация с <component :is="...">

Вместе со слотами можно динамически управлять не только содержимым, но и тем, в какой компонент вставляется контент:

&lt;component :is="currentView"&gt;
&lt;template #default&gt;
&lt;p&gt;Универсальный контент&lt;/p&gt;
&lt;/template&gt;
&lt;/component&gt;

Примеры из практики

Модальные окна:

&lt;Modal&gt;
&lt;template #header&gt;
&lt;h2&gt;Подтвердите действие&lt;/h2&gt;
&lt;/template&gt;
&lt;p&gt;Вы уверены, что хотите удалить?&lt;/p&gt;
&lt;template #footer&gt;
&lt;button&gt;Отмена&lt;/button&gt;
&lt;button&gt;Удалить&lt;/button&gt;
&lt;/template&gt;
&lt;/Modal&gt;

Модальное окно становится полностью переопределяемым, но логика его открытия/закрытия — остаётся в компоненте.

Кастомизация выпадающих списков

&lt;Dropdown :options="items"&gt;
&lt;template #option="{ option }"&gt;
&lt;div class="dropdown-option"&gt;
&lt;img :src="option.icon" /&gt;
&lt;span&gt;{{ option.label }}&lt;/span&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;/Dropdown&gt;

Позволяет полностью кастомизировать отображение каждого пункта выпадающего списка.

Когда стоит использовать слоты

Слоты особенно полезны, если:

  • Компонент не знает заранее, как будет выглядеть контент;

  • Нужно дать пользователю гибкость в кастомизации;

  • Повторяются одинаковые шаблоны с разным содержанием;

  • Требуется переиспользуемая структура (карточки, модалки, таблицы, лэйауты).

Слоты — это мощный инструмент Vue для создания гибких, универсальных и масштабируемых компонентов, в которых разделяется ответственность между логикой и отображением.