TGViewer
<divelopers> <divelopers> @alexnozer_dev · 1.18K subscribers
Post #375 731
Слоты без Shadow DOM

В HTML есть элемент <slot> и атрибут с таким же названием — slot. Работают они только с Shadow DOM. Цель элемента <slot> — обозначить стандартную или именованную ячейку для перемещения элементов из DOM в Shadow DOM.

Цель атрибута slot — указать имя ячейки, которую создаёт <slot name="…">, куда должен попасть элемент. Там ещё хитрые правила проникновения стилей в Shadow DOM и селекторы :slotted() и :has-slotted. Но это всё про Shadow DOM.

Я тут подумал: а если использовать атрибут slot без Shadow DOM? Так он не работает, но современный CSS на многое способен. Можно создать grid с именованными ячейками и распределить по ним элементы с помощью attr() и grid-area.

input-wrapper {
display: inline-grid;
grid-template-areas:
'label label label'
'before input after'
'info info info'
;

> :not([slot]) {
display: none !important;
}

> [slot] {
--slot: attr(
slot
type(label | before | input | after | info),
invalid
);
display: if(
style(--slot: invalid): none !important;
else: revert;
);
grid-area: if(
style(--slot: invalid): auto;
else: var(--slot);
);
}
}



<input-wrapper>
<label
for="pwd"
slot="label"
>
Пароль
</label>
<input
type="password"
id="pwd"
autocomplete="new-password"
slot="input"
>
<button
type="button"
commandfor="pwd"
command="--toggle-password"
slot="after"
aria-pressed="false"
>
<!-- ... -->
</button>
<p slot="info">
Пароль должен содержать...
</p>
</input-wrapper>


Сейчас объясню что тут происходит. Внутри input-wrapper объявлена сетка из трёх колонок с именованными ячейками label, before, input, after и info. Прямые потомки без атрибута slot скрываются, потому что он нужен.

Функция attr() считывает значение из атрибута slot и приводит его к заданному типу. Функция type() определяет CSS-тип значения, который представлен в виде перечисления доступных имён ячеек (как Union Type в Typescript).

Если в slot указано неподдерживаемое значение, то его не получится привести к типу, указанному в type(). В таком случае используется значение по умолчанию invalid. Результат attr() записывается в пользовательское свойство --slot.

Функция if() в свойстве display проверяет значение свойства --slot. Если там invalid, то есть в атрибуте задано неподдерживаемое имя ячейки, то такой элемент скрывается. Иначе revert возвращает заданное ранее значение.

В свойстве grid-area функция if() так же проверяет свойство --slot. При invalid устанавливается значение auto, но это не важно, потому что элемент будет скрыт. А если там допустимое значение, то элемент попадает в нужную ячейку.

Это работает в браузерах с поддержкой расширенной функции attr() и if(). Элементы можно менять местами и они всё равно попадут в нужные ячейки сетки. Ячейки могут быть пустыми, в примере нет элемента для слота before.

Это решение можно слегка деградировать, отказавшись от if() и attr() . Кода будет больше, но браузерная поддержка расширится и применить можно будет уже сейчас. Допустимые значения атрибута и ячейки нужно задать вручную.


input-wrapper {
/* ... */

> :is(
:not([slot]),
[slot]:not(
[slot="label"],
[slot="before"],
...
)
)
{
display: none !important;
}

> [slot="label"] {
grid-area: label;
}

> [slot="before"] {
grid-area: before;
}

...
}


Я использую пользовательский элемент <input-wrapper> как обёртку, без JS. Удобно и логично, что имя контейнера намекает на суть. Можно использовать <div class="input-wrapper">, если так удобнее и привычнее.

Так на HTML и CSS можно создавать компоненты с некоторым API «слотов». И использование для этого существующего атрибута slot выглядит логично, хотя и не по назначению. Можно в случае чего заменить на data-slot.

#css
  • 🔥 4
  • 🤯 4
  • ❤ 1
  • 😱 1
  • 🗿 1
More from @alexnozer_dev
  1. Sep 21, 2026Реализация пользовательских атрибутов Под конец прошлого года я рассказывал об API пользов…
  2. Sep 14, 2026Подклассы Event вместо CustomEvent Многие библиотеки предоставляют систему событий в качес…
  3. Sep 11, 2026Эволюция стилей в темах Shopify Адам Ватан на днях поделился новостью, что Shopify выкупил…
  4. Sep 9, 2026Persistent Widgets Многие сайты не должны быть SPA. Но иногда эта архитектура продиктована…
  5. Sep 7, 2026Processing Instructions и маркеры В DOM всё представлено в виде узлов (Node) разных типов.…
  6. Sep 1, 2026@scope и потоковая передача HTML Ноам Розенталь поделился интересной техникой, в которой с…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →