Web Components — Custom Elements и Shadow DOM
Web Components - состав стандарта
Web Components — набор браузерных стандартов для переиспользуемых UI-блоков без обязательного React/Vue:
- Custom Elements — свои теги (
<user-card>). - Shadow DOM — изолированное поддерево DOM и стили внутри компонента.
- HTML templates —
<template>для клонирования разметки. - Slots — точки вставки внешнего контента в шаблон.
Фреймворки (React, Vue, Angular) часто используют Shadow DOM выборочно или эмулируют инкапсуляцию по-своему. Нативные компоненты уместны в дизайн-системах, embed-виджетах и постепенной модернизации статичных страниц.
Предварительно: классы, работа с DOM, события.
Custom Elements
Класс наследует HTMLElement, регистрируется один раз:
class UserCard extends HTMLElement {
connectedCallback() {
if (this._ready) return;
this._ready = true;
const name = this.getAttribute('name') ?? 'Гость';
this.innerHTML = `
<article class="user-card">
<h2>${escapeHtml(name)}</h2>
<slot></slot>
</article>
`;
}
static get observedAttributes() {
return ['name'];
}
attributeChangedCallback(attr, oldVal, newVal) {
if (attr === 'name' && oldVal !== newVal) {
this._ready = false;
this.connectedCallback();
}
}
}
function escapeHtml(text) {
return text
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>');
}
customElements.define('user-card', UserCard);
| Хук | Когда вызывается |
|---|---|
connectedCallback | элемент добавлен в документ |
disconnectedCallback | удалён из документа |
attributeChangedCallback | изменился атрибут из observedAttributes |
adoptedCallback | элемент перенесли в другой документ (редко) |
Использование в HTML:
<user-card name="Анна">
<p>Менеджер проекта</p>
</user-card>
Имена custom elements обязаны содержать дефис (user-card), чтобы не пересечься со встроенными тегами.
Shadow DOM
attachShadow() создаёт отдельное дерево, стили снаружи не проникают внутрь (и наоборот — с оговорками для CSS-переменных).
class StatusBadge extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = `
<style>
:host {
display: inline-block;
font: 14px/1.4 system-ui, sans-serif;
}
.badge {
padding: 2px 8px;
border-radius: 999px;
background: var(--badge-bg, #e0e0e0);
}
</style>
<span class="badge"><slot></slot></span>
`;
}
}
customElements.define('status-badge', StatusBadge);
mode | Поведение |
|---|---|
open | element.shadowRoot доступен снаружи |
closed | shadowRoot снаружи null (как у встроенного <video>) |
:host — стили самого хост-элемента. :host([active]) — при атрибуте active.
Слоты
<slot name="..."> — место, куда попадает разметка светлого DOM (дети custom element):
<article-panel>
<h2 slot="title">Новости</h2>
<p>Текст блока</p>
</article-panel>
// в shadow:
// <header><slot name="title"></slot></header>
// <div class="body"><slot></slot></div> <!-- default slot -->
События со слотов всплывают с пометкой, что прошли через shadow boundary — учитывайте при делегировании.
Шаблон template
Разметку удобно хранить в <template> и клонировать:
<template id="todo-item-tpl">
<li><button type="button" class="done">✓</button> <span class="text"></span></li>
</template>
const tpl = document.getElementById('todo-item-tpl');
const node = tpl.content.cloneNode(true);
node.querySelector('.text').textContent = 'Купить молоко';
list.appendChild(node);
В связке с Shadow DOM шаблон кладут внутрь shadow root при инициализации.
События и публичный API
- Внутри класса вызывайте
this.dispatchEvent(new CustomEvent('save', { detail: { id: 1 }, bubbles: true }))— слушатели на странице поймают событие приbubbles: true. - Публичные методы на классе (
show(),reset()) вызывают снаружи:document.querySelector('user-card').focus().
Не экспонируйте внутренние узлы shadow root в продакшене — это ломает инкапсуляцию.
Когда брать Web Components, когда фреймворк
| Ситуация | Подход |
|---|---|
| Виджет на чужой CMS, один тег на странице | Custom Element + Shadow |
| Большое SPA, команда на React | React; web components для изолированных legacy-блоков |
| Дизайн-система для нескольких стеков | Stencil/Lit → web components |
| Простой сайт без сборки | Ванильный JS (виджеты) может быть проще |
Минусы нативных компонентов: нет встроенного виртуального DOM, сложнее тестировать без браузера, SSR требует отдельных решений.
Краткий итог
Custom Elements дают свой тег и жизненный цикл. Shadow DOM изолирует разметку и CSS. Slots подключают внешний контент. Стандарты дополняют, а не обязаны заменять фреймворки — но полезны там, где нужен один переиспользуемый блок в любом окружении.
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Основы JavaScript - стандарт ECMAScript, модель выполнения и базовые конструкции языка. JavaScript — это язык программирования, который позволяет создавать интерактивные веб-страницы, серверные приложения и мобильные программы. Для создания массивов используется литеральная нотация. Конструктор Array не применяется. Как работать с HTML-элементами, как их создавать, менять. Простые приложения на JavaScript - базовые сценарии, структура кода и быстрый старт с практическими примерами. Расширения файлов определяют способ обработки кода средой выполнения или компилятором. История JavaScript - происхождение языка, ключевые этапы развития и влияние на современный веб. Такое именование представляет собой соглашение между разработчиками. Классический JavaScript не обеспечивает реальной приватности через подчеркивания. JavaScript содержит набор зарезервированных слов, которые имеют специальное значение в языке. Эти слова нельзя использовать в качестве идентификаторов для переменных, функций или классов. Встроенные функции JavaScript - ключевые методы массивов, строк и объектов для повседневной разработки. Этот шаблон описывает подключение внешних функций, классов или значений из других файлов. Он используется в начале файла и определяет зависимости текущего модуля. JavaScript используется для создания кроссплатформенных мобильных приложений, которые работают на iOS и Android с использованием единой кодовой базы.Основы JavaScript
Что требуется знать перед началом изучения языка программирования JavaScript
Рекомендации по разработке на JavaScript
Работа с HTML в JavaScript
Простые приложения на JavaScript
Форматы JavaScript
История языка JavaScript
Синтаксис и пунктуация в JavaScript
Ключевые слова языка JavaScript
Встроенные функции JavaScript
Структура и подключение JavaScript-кода
Применение JavaScript в вебе и за его пределами