Web Components — Custom Elements и Shadow DOM
Web Components - состав стандарта
Web Components — это набор стандартизированных браузерных технологий и спецификаций, который позволяет разработчикам создавать собственные переиспользуемые пользовательские элементы на чистом HTML, CSS и JavaScript без использования сторонних фреймворков, обеспечивая инкапсуляцию стилей и логики внутри компонента для безопасного и предсказуемого использования в любых веб-приложениях. Технология Web Components объединяет в себе четыре ключевых стандарта: Custom Elements для определения новых HTML-тегов, Shadow DOM для инкапсуляции внутренней структуры и стилей компонента, HTML Templates для объявления статических фрагментов разметки, которые могут быть клонированы и использованы многократно, и HTML Imports, которые в настоящее время считаются устаревшими и заменены на ES-модули. Web Components решают давнюю проблему веб-разработки, связанную с отсутствием встроенного механизма для создания изолированных и самодостаточных компонентов, которые можно легко переносить между проектами и делиться с сообществом, обеспечивая при этом, чтобы стили и поведение одного компонента не влияли на другие элементы страницы. Основная идея Web Components заключается в том, чтобы сделать веб-платформу более компонентно-ориентированной, расширив возможности HTML и позволив разработчикам создавать собственные семантические теги, такие как или , которые ведут себя как встроенные элементы браузера, поддерживают атрибуты, события и методы, и могут быть использованы в любом фреймворке или без него. Благодаря тому, что Web Components являются нативными браузерными стандартами, они не требуют загрузки дополнительных библиотек для работы, что делает их легковесными и быстрыми, а их поддержка во всех современных браузерах постоянно растет, что подтверждает их долгосрочную жизнеспособность и важность для будущего веб-разработки. Web Components особенно полезны для создания дизайн-систем и библиотек компонентов, которые должны работать единообразно в различных проектах, технологических стеках и средах, а также для создания микрофронтендов и изолированных виджетов, встраиваемых на страницы, где основной код написан на любом другом фреймворке.
Браузерный стандарт — это официальная спецификация, разработанная и поддерживаемая организациями по стандартизации, такими как W3C и WHATWG, которая определяет, как определенная технология или API должны быть реализованы в веб-браузерах, чтобы обеспечивать единообразное поведение и совместимость на всех платформах и устройствах, гарантируя предсказуемость для разработчиков и пользователей. Браузерные стандарты охватывают все аспекты веб-платформы, включая HTML для структуры документов, CSS для стилизации, JavaScript для поведения, а также множество специализированных API, таких как DOM, Canvas, WebGL, Web Components и Push API, каждый из которых проходит долгий путь от черновика через рабочий проект до финальной рекомендации. Процесс создания браузерного стандарта включает многолетнюю работу экспертов из ведущих компаний, таких как Google, Apple, Microsoft и Mozilla, а также независимых разработчиков, которые совместно обсуждают спецификацию, пишут черновики, реализуют экспериментальные версии в своих браузерах и собирают обратную связь от сообщества, чтобы прийти к консенсусу по наилучшей реализации. Следование браузерным стандартам означает, что разработчик может полагаться на то, что его код будет работать одинаково в Chrome, Firefox, Safari, Edge и других браузерах, без необходимости писать отдельные версии для каждого браузера или использовать сложные обходные пути, что значительно упрощает разработку и поддержку веб-приложений. Браузерные стандарты также определяют не только синтаксис и функциональность, но и политики безопасности, производительности, доступности и конфиденциальности, обеспечивая, чтобы веб-платформа оставалась безопасной и инклюзивной для всех пользователей, независимо от их устройств или способностей. Развитие браузерных стандартов является эволюционным процессом, где новые возможности добавляются постепенно, а устаревшие удаляются, при этом организации по стандартизации стремятся поддерживать обратную совместимость, чтобы существующие сайты не переставали работать, и одновременно внедрять инновации, которые открывают новые горизонты для веб-разработчиков.
Web Components — набор браузерных стандартов для переиспользуемых UI-блоков без обязательного React/Vue:
- Custom Elements — свои теги (
<user-card>). - Shadow DOM — изолированное поддерево DOM и стили внутри компонента.
- HTML templates —
<template>для клонирования разметки. - Slots — точки вставки внешнего контента в шаблон.
Фреймворки (React, Vue, Angular) часто используют Shadow DOM выборочно или эмулируют инкапсуляцию по-своему. Нативные компоненты уместны в дизайн-системах, embed-виджетах и постепенной модернизации статичных страниц.
Предварительно: классы, работа с DOM, события.
Когда выбирать Web Components
Переиспользуемые UI-блоки — это самодостаточные, независимые части пользовательского интерфейса, которые инкапсулируют в себе структуру, внешний вид и поведение, и могут быть использованы многократно в различных частях одного приложения, а также переноситься между разными проектами, существенно сокращая время разработки и повышая согласованность и качество интерфейса. В контексте Web Components переиспользуемые UI-блоки создаются с использованием Custom Elements и Shadow DOM, что позволяет разработчику определить новый HTML-тег, который представляет собой целостный компонент, например, кнопку с иконкой, карточку товара, модальное окно или сложный графический виджет, и затем использовать этот тег в любом месте страницы так же легко, как встроенные элементы div или span. Переиспользуемые UI-блоки должны быть спроектированы таким образом, чтобы они были гибкими и настраиваемыми через атрибуты, свойства и слоты, позволяя разработчику изменять их содержание, стиль или поведение в зависимости от контекста использования, но при этом сохранять внутреннюю целостность и не требовать от пользователя компонента глубокого понимания его внутренней реализации. Основные преимущества переиспользуемых UI-блоков включают уменьшение дублирования кода, поскольку однажды написанный и отлаженный компонент можно использовать множество раз, ускорение разработки новых функций благодаря готовым строительным блокам, улучшение поддерживаемости, поскольку изменения в одном месте автоматически распространяются на все использования, и повышение качества, поскольку компоненты проходят более тщательное тестирование при многократном использовании. Важной практикой при создании переиспользуемых UI-блоков является их документирование, создание примеров использования и тестирование в различных сценариях, чтобы гарантировать их надежность и удобство для других разработчиков, а также формирование библиотеки компонентов, которая служит единым источником истины для всего интерфейса приложения. С развитием веб-технологий концепция переиспользуемых UI-блоков стала центральной в современной веб-разработке, причем Web Components предоставляют нативный способ их реализации, независимый от фреймворков, что делает их идеальным выбором для создания кросс-проектных решений.
Имеет смысл, если один UI-блок нужен в разных стеках — статический сайт, SPA, CMS, embed у партнёра. Нативные Custom Elements + Shadow DOM дают долгоживущий контракт без привязки к React/Vue; фреймворки при этом могут использовать Shadow DOM выборочно или эмулировать инкапсуляцию своим способом.
Custom Elements
Custom Elements — это один из ключевых стандартов спецификации Web Components, который позволяет разработчикам создавать собственные HTML-элементы с уникальными тегами, определяя их поведение, внешний вид и API с использованием JavaScript, тем самым расширяя возможности HTML и позволяя создавать новые семантические конструкции, которые органично вписываются в веб-платформу. Custom Elements делятся на два типа: автономные элементы, которые наследуются от базового класса HTMLElement и создают совершенно новые теги, не связанные с существующими HTML-элементами, и наследуемые элементы, которые расширяют функциональность уже существующих встроенных элементов, например, button или input, добавляя им новое поведение через наследование от соответствующих классов. Для создания Custom Element разработчик определяет класс, расширяющий соответствующий базовый класс HTMLElement, описывает в нем жизненный цикл компонента через специальные методы, такие как constructor для инициализации, connectedCallback для логики при подключении к DOM, disconnectedCallback для очистки при удалении, и attributeChangedCallback для реакции на изменения атрибутов, а затем регистрирует новый элемент с помощью метода customElements.define, передавая ему имя тега и класс. Основное преимущество Custom Elements заключается в том, что они становятся полноправными гражданами DOM, поддерживают все стандартные операции, такие как поиск через querySelector, манипуляции атрибутами, работу с событиями и стилизацию, и могут быть использованы в любом фреймворке или без него, что делает их универсальным решением для создания компонентов. Custom Elements также поддерживают статические свойства observedAttributes, которые позволяют объявить атрибуты, за изменением которых должен следить компонент, и автоматически вызывать attributeChangedCallback при их изменении, что обеспечивает реактивность и синхронизацию состояния компонента с внешним миром. Благодаря своей нативной природе и широкой поддержке в браузерах, Custom Elements становятся все более популярным способом создания компонентов, которые работают везде и не зависят от конкретной экосистемы, что делает их идеальным выбором для долгосрочных проектов и библиотек UI-компонентов.
Класс наследует HTMLElement, регистрируется один раз:
Код ITЗагрузка примера кода…
Разбор:
- В этом фрагменте используется конструкция
class UserCard extends HTMLElement {как точка входа сценария. - Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
- Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
Хук — это термин, который в контексте программирования и веб-разработки обозначает функцию или механизм, позволяющий "подключаться" к внутреннему состоянию, жизненному циклу или поведению компонента или системы, предоставляя разработчику возможность влиять на их работу без необходимости переопределять или наследовать всю структуру, что делает код более гибким, читаемым и переиспользуемым. В контексте Web Components понятие хука не является строго определенным стандартом, но часто используется для обозначения методов жизненного цикла, таких как connectedCallback, disconnectedCallback и attributeChangedCallback, которые позволяют разработчику "зацепиться" за определенные моменты существования компонента в DOM и выполнить необходимые действия при его создании, подключении к странице, обновлении или удалении. В более широком смысле, хук может относиться к любому API или функции, которая позволяет расширить или модифицировать поведение системы в определенных точках, например, хуки в React, которые дают возможность использовать состояние и другие возможности функциональных компонентов, или хуки в системах управления контентом, которые позволяют модифицировать данные перед их отображением. Использование хуков обычно делает код более модульным и тестируемым, поскольку логика, связанная с определенными аспектами поведения, может быть выделена в отдельные функции и повторно использована в разных компонентах, уменьшая дублирование и улучшая поддержку. В контексте Web Components хуки часто реализуются в виде классов-миксинов или декораторов, которые добавляют дополнительную функциональность к пользовательским элементам, позволяя, например, подключать управление состоянием, обработку событий или интеграцию с другими библиотеками без загрязнения основного класса. Понимание и использование хуков является важной частью современной веб-разработки, поскольку они предоставляют элегантный способ организации кода и управления сложностью, особенно в крупных приложениях с множеством взаимодействующих компонентов и состояний.
| Хук | Когда вызывается |
|---|---|
connectedCallback | элемент добавлен в документ |
disconnectedCallback | удалён из документа |
attributeChangedCallback | изменился атрибут из observedAttributes |
adoptedCallback | элемент перенесли в другой документ (редко) |
Использование в HTML:
<user-card name="Анна">
<p>Менеджер проекта</p>
</user-card>
Разбор:
- В этом фрагменте используется конструкция
<user-card name="Анна">как точка входа сценария. - Разметка задаёт опорные элементы интерфейса, к которым затем подключается JavaScript-логика.
- Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
Имена custom elements обязаны содержать дефис (user-card), чтобы не пересечься со встроенными тегами.
Shadow DOM
Shadow DOM — это один из ключевых стандартов спецификации Web Components, который предоставляет механизм инкапсуляции для DOM-дерева и CSS-стилей компонента, позволяя создавать отдельное изолированное поддерево DOM, которое прикрепляется к пользовательскому элементу и невидимо для основного документа, защищая внутреннюю структуру и стили компонента от влияния внешнего мира и наоборот. Shadow DOM создается с помощью метода attachShadow, который вызывается на экземпляре Custom Element, и этот метод возвращает корневой узел теневого DOM, в который можно добавлять дочерние элементы, так же как в обычный DOM, но при этом все эти элементы не видны при стандартных операциях поиска из внешнего документа, таких как querySelector, и их стили не пересекаются со стилями основной страницы. Основное преимущество Shadow DOM заключается в том, что он решает фундаментальную проблему CSS-каскада и конфликтов стилей, поскольку стили, определенные внутри теневого DOM, остаются локальными и не влияют на внешние элементы, а стили из внешнего документа не проникают внутрь теневого DOM без явного разрешения через CSS-переменные или специальные псевдоклассы, что делает компоненты надежными и предсказуемыми в любом окружении. Shadow DOM также изолирует события, поскольку события, происходящие внутри теневого DOM, могут быть настроены на всплытие за пределы тени, но при этом они ретаргетируются, то есть их целевой элемент заменяется на элемент-хост, что предотвращает утечку внутренней структуры компонента во внешний мир и сохраняет инкапсуляцию. Существует два режима работы Shadow DOM: открытый режим, при котором доступ к корню теневого DOM возможен из внешнего кода через свойство shadowRoot, что полезно для отладки и расширения функциональности, и закрытый режим, при котором доступ к shadowRoot блокируется, обеспечивая максимальную изоляцию, хотя последний режим используется редко из-за ограничений в отладке и тестировании. Благодаря Shadow DOM веб-разработчики получили инструмент, который позволяет создавать компоненты с гарантированной изоляцией, что особенно важно для библиотек компонентов, дизайн-систем и сторонних виджетов, которые должны выглядеть и работать одинаково на любых страницах, независимо от глобальных стилей и скриптов, присутствующих на этих страницах.
attachShadow() создаёт отдельное дерево, стили снаружи не проникают внутрь (и наоборот — с оговорками для CSS-переменных).
Код ITЗагрузка примера кода…
Разбор:
- В этом фрагменте используется конструкция
class StatusBadge extends HTMLElement {как точка входа сценария. - Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
- Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
mode | Поведение |
|---|---|
open | element.shadowRoot доступен снаружи |
closed | shadowRoot снаружи null (как у встроенного <video>) |
:host — стили самого хост-элемента. :host([active]) — при атрибуте active.
Слоты
Слоты — это механизм внутри Shadow DOM, который позволяет создавать точки вставки контента, переданного от пользователя компонента, предоставляя гибкий способ управления тем, какое содержимое будет отображаться в определенных местах теневой структуры, и тем самым делая компоненты настраиваемыми и адаптируемыми без необходимости переопределять всю их внутреннюю разметку. Слоты определяются внутри теневого DOM с помощью элемента slot, который может иметь атрибут name для создания именованных слотов, и когда компонент используется в основном документе, любой дочерний контент, помещенный внутрь пользовательского элемента, автоматически распределяется по соответствующим слотам на основе соответствия атрибута slot на дочерних элементах или по умолчанию в неименованный слот. Если пользователь не предоставляет контент для определенного слота, слот может содержать резервное содержимое, которое будет отображаться по умолчанию, что делает компоненты удобными для использования "из коробки" с типовым содержимым и при этом гибкими для кастомизации в особых случаях. Слоты не только распределяют содержимое, но и сохраняют его логическую принадлежность к основному документу, то есть элементы, помещенные в слот, продолжают быть частью легкого DOM и сохраняют свои стили из внешнего документа, а также могут быть найдены через обычные DOM-запросы в контексте основного документа, что позволяет комбинировать локальные стили теневого DOM и внешние стили для содержимого слотов. Использование слотов делает Web Components более декларативными и интуитивно понятными для разработчиков, поскольку они могут использовать знакомый HTML-синтаксис для передачи контента в компонент, как это делается с обычными HTML-элементами, но при этом получают мощную инкапсуляцию и логику от компонента. Слоты также поддерживают сложные сценарии, включая вложенные слоты и динамическое изменение распределения контента при изменении DOM, что позволяет создавать компоненты с адаптивным и реактивным поведением, например, аккордеоны, табы, модальные окна и сложные карточки, где структура и содержимое могут варьироваться в широких пределах.
<slot name="..."> — место, куда попадает разметка светлого DOM (дети custom element):
<article-panel>
<h2 slot="title">Новости</h2>
<p>Текст блока</p>
</article-panel>
Разбор:
- В этом фрагменте используется конструкция
<article-panel>как точка входа сценария. - Разметка задаёт опорные элементы интерфейса, к которым затем подключается JavaScript-логика.
- Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
// в shadow:
// <header><slot name="title"></slot></header>
// <div class="body"><slot></slot></div> <!-- default slot -->
Разбор:
- В этом фрагменте используется конструкция
// в shadow:как точка входа сценария. - Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
- Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
События со слотов всплывают с пометкой, что прошли через shadow boundary — учитывайте при делегировании.
Шаблон template
Шаблон template — это стандартный HTML-элемент, который используется для объявления фрагментов разметки, которые не отображаются на странице при загрузке, но могут быть программно клонированы и вставлены в DOM позже с помощью JavaScript, что обеспечивает эффективный способ создания повторяющихся структур и динамической генерации контента без необходимости конструировать сложные строки с HTML-разметкой в коде. Элемент template является частью спецификации HTML и содержимое внутри него не обрабатывается браузером при рендеринге, то есть изображения не загружаются, скрипты не выполняются, а стили не применяются до тех пор, пока содержимое шаблона не будет активировано через JavaScript, что делает его безопасным и производительным способом хранения разметки для будущего использования. В контексте Web Components шаблоны часто используются вместе с Custom Elements и Shadow DOM для объявления внутренней структуры компонента, где разработчик помещает все необходимые элементы, стили и даже вспомогательные скрипты внутри шаблона, а затем в конструкторе или connectedCallback компонента клонирует содержимое шаблона и присоединяет его к теневому корню, создавая таким образом эффективный и поддерживаемый способ определения разметки компонента. Клонирование содержимого шаблона обычно выполняется с помощью метода document.importNode или через метод cloneNode, который создает глубокую копию всех элементов, включая их атрибуты и дочерние узлы, и эта операция является производительной, поскольку браузер не выполняет повторный парсинг HTML при каждом клонировании. Шаблоны поддерживают использование слотов внутри своего содержимого, что позволяет создавать гибкие компоненты, где структура определена в шаблоне, а содержимое может быть предоставлено пользователем компонента через слоты, обеспечивая разделение структуры и контента. Использование шаблонов является лучшей практикой при создании Web Components и любых других динамических веб-приложений, поскольку оно отделяет разметку от логики, упрощает поддержку и модификацию интерфейса, а также позволяет браузеру оптимизировать обработку неактивного контента, что положительно сказывается на производительности и потреблении памяти.
Разметку удобно хранить в <template> и клонировать:
<template id="todo-item-tpl">
<li><button type="button" class="done">✓</button> <span class="text"></span></li>
</template>
Разбор:
- В этом фрагменте используется конструкция
<template id="todo-item-tpl">как точка входа сценария. - Разметка задаёт опорные элементы интерфейса, к которым затем подключается JavaScript-логика.
- Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
const tpl = document.getElementById('todo-item-tpl');
const node = tpl.content.cloneNode(true);
node.querySelector('.text').textContent = 'Купить молоко';
list.appendChild(node);
Разбор:
- В этом фрагменте используется конструкция
const tpl = document.getElementById('todo-item-tpl');как точка входа сценария. - Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
- Поиск элементов через
querySelectorявно привязывает сценарий к нужным узлам DOM. - Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
В связке с Shadow DOM шаблон кладут внутрь shadow root при инициализации.
События и публичный API
События — это фундаментальный механизм коммуникации в веб-приложениях, который позволяет компонентам и элементам DOM взаимодействовать друг с другом и реагировать на действия пользователя, изменения состояния или системные уведомления, создавая интерактивный и отзывчивый пользовательский интерфейс. В контексте Web Components события играют особенно важную роль, поскольку они являются основным способом передачи информации из внутреннего изолированного пространства Shadow DOM во внешний мир, позволяя компоненту уведомлять родительские элементы о произошедших изменениях, действиях пользователя или ошибках, сохраняя при этом инкапсуляцию и не раскрывая свою внутреннюю структуру. При создании пользовательских элементов разработчик может генерировать пользовательские события с помощью конструктора CustomEvent, передавая в него имя события и дополнительные данные в свойстве detail, а затем диспетчеризировать это событие с помощью метода dispatchEvent на элементе-хосте или на любом другом элементе внутри компонента, при этом важно настроить свойство bubbles и composed для управления всплытием и выходом за пределы теневой границы. События в Web Components могут быть как встроенными, такими как клик, мышь, клавиатура, изменение, так и пользовательскими, определенными разработчиком для конкретных случаев, например, событие item-selected при выборе элемента в списке, или событие value-changed при изменении значения в кастомном поле ввода, что делает компоненты выразительными и удобными для интеграции в любые приложения. Особенностью событий, происходящих из Shadow DOM, является их ретаргетинг на элемент-хост при пересечении границы тени, что означает, что внешний обработчик события видит в свойстве target не внутренний элемент, на котором произошло событие, а сам пользовательский элемент, что скрывает детали реализации компонента и упрощает работу с ним извне. Документирование всех событий, которые может генерировать компонент, а также создание четкого и последовательного API для их обработки, является важной частью разработки качественных Web Components, поскольку это позволяет разработчикам, использующим компонент, легко интегрировать его в свои приложения и правильно реагировать на все возможные состояния и действия.
Публичный API — это совокупность свойств, методов, атрибутов и событий, которые разработчик компонента намеренно делает доступными для внешнего использования, определяя таким образом контракт между компонентом и его пользователями, и обеспечивая четкий и стабильный интерфейс для взаимодействия, в то время как все внутренние детали реализации остаются скрытыми и инкапсулированными. В контексте Web Components публичный API включает в себя HTML-атрибуты, которые пользователь может устанавливать на пользовательском элементе для конфигурации его начального состояния, JavaScript-свойства, которые можно читать и устанавливать для управления состоянием компонента, методы, которые можно вызывать для выполнения определенных действий, такие как открытие или закрытие модального окна, и события, на которые пользователь может подписываться для получения уведомлений о происходящих внутри компонента изменениях. Разработка хорошо продуманного публичного API является одной из ключевых задач при создании переиспользуемых компонентов, поскольку от него зависит, насколько легко и интуитивно компонент будет использоваться другими разработчиками, насколько гибко он сможет адаптироваться к различным сценариям использования и насколько просто будет его поддерживать и обновлять в будущем. Важными принципами проектирования публичного API являются простота и минимализм, когда API содержит только самое необходимое и не перегружено избыточными или малопонятными методами, а также согласованность, когда все методы и свойства следуют единым паттернам именования и поведения, что делает компонент предсказуемым и легким для изучения. Документирование публичного API является неотъемлемой частью процесса разработки, поскольку без качественной документации даже самый лучший компонент останется невостребованным или будет использоваться неправильно, поэтому разработчики создают подробные README-файлы, примеры использования, интерактивные демонстрации и часто используют инструменты для автоматической генерации документации на основе JSDoc-комментариев или TypeScript-типов. При обновлении компонента разработчики должны соблюдать семантическое версионирование, где изменения, нарушающие обратную совместимость публичного API, требуют увеличения мажорной версии, а добавление новых возможностей без нарушения существующего 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 требует отдельных решений.
Практический маршрут внедрения
Если команда только начинает использовать Web Components, удобен поэтапный план:
- Выделить один изолированный UI-блок (badge, card, date-picker).
- Описать публичный API компонента через атрибуты, свойства и кастомные события.
- Сделать shadow-стили и проверить совместимость в текущей теме сайта.
- Подключить компонент в 2-3 разных страницах или сервисах.
- Зафиксировать контракт в документации дизайн-системы.
Так формируется стабильная библиотека компонентов, которую используют проекты на разных стеках.
Частые ошибки интеграции
- Компонент напрямую манипулирует глобальным CSS и ломает внешние страницы.
- Внутренние DOM-узлы возвращаются наружу как часть API, и инкапсуляция теряет смысл.
- События не помечаются
bubbles: true, из-за чего родительские контейнеры их не получают. - Логика рендера выполняется при каждом
attributeChangedCallbackбез проверки изменений, что создаёт лишние перерисовки.
Для сценариев с формами и сетью сочетайте web components с валидацией и отменой запросов.
Краткий итог
Custom Elements дают свой тег и жизненный цикл. Shadow DOM изолирует разметку и CSS. Slots подключают внешний контент. Стандарты дополняют, а не обязаны заменять фреймворки — но полезны там, где нужен один переиспользуемый блок в любом окружении.