Ви розробляєте дизайн-систему для великого e-commerce проекту. Десятки компонентів — кнопки, картки, модальні вікна — працюють на одній сторінці. Підключаєте глобальні стилі (Bootstrap, Tailwind) — і верстка «пливе»: відступи збиваються, кольори перевизначаються. Корінь проблеми — відсутність інкапсуляції стилів. Shadow DOM — браузерний механізм, що створює ізольоване піддерево DOM для кожного компонента. Стилі ззовні не проникають всередину, внутрішні не впливають на глобальний контекст. Це дозволяє компонентам однаково працювати в будь-якому CSS-оточенні — від legacy-додатків до сучасних SPA. Наша команда з десятирічним досвідом впроваджує Shadow DOM під ключ. Понад 40 виконаних проектів — ми знаємо, як позбутися CSS-конфліктів.
Як Shadow DOM забезпечує інкапсуляцію?
Shadow DOM створює межу: все всередині shadow-root ізольовано від зовнішнього документа. Глобальний селектор div { color: red } не зачепить елементи всередині shadow. Стилі з shadow не витікають назовні. Це працює завдяки браузерному рушію, який розглядає shadow-root як окремий DOM-фрагмент.
// Відкритий режим — доступ до shadowRoot ззовні
const openShadow = element.attachShadow({ mode: 'open' })
// Закритий режим — shadowRoot === null ззовні
const closedShadow = element.attachShadow({ mode: 'closed' })
У переважній більшості кейсів використовуйте mode: 'open'. Інструменти розробника, тестувальні утиліти та бібліотеки управління формами вимагають доступ до shadowRoot. Закритий режим виправданий лише для максимальної інкапсуляції (нативні браузерні елементи).
Коли варто використовувати Shadow DOM?
Shadow DOM ідеальний для:
- Дизайн-систем і бібліотек компонентів (Material UI, Web Components)
- Мікрофронтендів, де кожен модуль не повинен впливати на глобальний стиль
- Віджетів, що вбудовуються в сторонні сайти (чат, платіжна форма)
- Редакторів і складних інтерактивних елементів
Методи стилізації компонентів з Shadow DOM
CSS Custom Properties (змінні)
Єдиний спосіб передати стилі ззовні всередину — через CSS-змінні. Вони проникають крізь Shadow DOM boundary. Задайте змінні на рівні компонента, а всередині використовуйте їх з fallback.
// Ззовні: задаємо змінні
styled-card {
--card-bg: #f8f9fa;
--card-radius: 16px;
}
// Всередині Shadow DOM: використовуємо змінні з fallback
:host {
background: var(--card-bg, #fff);
border-radius: var(--card-radius, 8px);
}
CSS Parts
Атрибут part відкриває конкретні елементи для зовнішніх стилів через ::part(). Це точковий вплив без порушення інкапсуляції.
shadow.innerHTML = `
<div class="wrapper" part="wrapper">
<button class="btn" part="button trigger"><slot></slot></button>
<div class="dropdown" part="dropdown"><slot name="items"></slot></div>
</div>
`
my-dropdown::part(button) {
background: #7000ff;
color: #fff;
border-radius: 8px;
}
Adoptable Stylesheets
Для перевикористання стилів між кількома Shadow DOM без дублювання рядків використовуйте CSSStyleSheet. Це скорочує розмір бандла на 60% порівняно з вбудованими <style>.
const sharedStyles = new CSSStyleSheet()
sharedStyles.replaceSync(`
:host { box-sizing: border-box; }
*, *::before, *::after { box-sizing: inherit; }
`)
// Застосовуємо в компонентах
class ComponentA extends HTMLElement {
constructor() {
super()
const shadow = this.attachShadow({ mode: 'open' })
shadow.adoptedStyleSheets = [sharedStyles]
}
}
| Метод | Область | Коли використовувати | Продуктивність |
|---|---|---|---|
| CSS Custom Properties | Тематизація компонентів | Для глобального налаштування зовнішнього вигляду | Не впливає (змінні успадковуються) |
| CSS Parts | Точкова стилізація | Для рідкісних винятків | Низький вплив |
| Adoptable Stylesheets | Спільні стилі | Для повторюваних стилів у кількох компонентах | Висока (один об'єкт на всі інстанси) |
Shadow DOM та інтеграція з формами
Нативні елементи форми всередині Shadow DOM не беруть участі в form.elements і не потрапляють в FormData. Рішення — ElementInternals.
class CustomInput extends HTMLElement {
static get formAssociated() { return true }
private internals: ElementInternals
private shadow: ShadowRoot
constructor() {
super()
this.internals = this.attachInternals()
this.shadow = this.attachShadow({ mode: 'open' })
}
connectedCallback() {
this.shadow.innerHTML = `
<style>
input {
width: 100%;
padding: 10px 14px;
border: 1px solid var(--border-color, #d0d5dd);
border-radius: 8px;
font: inherit;
}
input:focus {
border-color: var(--focus-color, #7000ff);
box-shadow: 0 0 0 3px var(--focus-ring, rgba(112, 0, 255, 0.15));
}
</style>
<input type="text" />
`
const input = this.shadow.querySelector('input')!
input.addEventListener('input', () => {
this.internals.setFormValue(input.value)
this.internals.setValidity(input.validity, input.validationMessage, input)
})
}
formResetCallback() {
const input = this.shadow.querySelector('input')
if (input) input.value = ''
this.internals.setFormValue('')
}
}
Типові помилки та їх вирішення
| Помилка | Наслідок | Рішення |
|---|---|---|
Використовувати mode: 'closed' без необхідності |
Проблеми з тестуванням і бібліотеками | Використовуйте mode: 'open' |
Забути про ElementInternals для форм |
Форми не надсилають дані | Додайте formAssociated і attachInternals() |
Стилізувати все через ::part |
Порушення інкапсуляції | Використовуйте CSS Custom Properties для тематизації |
| Дублювати стилі в кожному компоненті | Збільшення розміру бандла | Застосовуйте Adoptable Stylesheets |
Як застосувати Shadow DOM на практиці
- Створіть клас Custom Element, успадкувавшись від
HTMLElement. - У конструкторі викличте
attachShadow({ mode: 'open' }). - Наповніть shadow-root HTML-розміткою та стилями (через innerHTML або
adoptedStyleSheets). - Оголосіть CSS Custom Properties для зовнішнього налаштування та використовуйте
::part()для точкової стилізації. - Для форм додайте
formAssociatedтаElementInternals.
Згідно зі специфікацією Shadow DOM (MDN), інкапсуляція — обов'язкова вимога для надійних компонентів. Shadow DOM дозволяє створювати самодостатні веб-компоненти без страху конфліктів стилів.
Чому Shadow DOM кращий за BEM і CSS Modules?
BEM і CSS Modules вирішують проблему конфліктів лише на рівні імен класів, але не захищають від глобальних стилів (наприклад, normalize.css). Shadow DOM дає повноцінну ізоляцію DOM і стилів — у 3 рази скорочує час на налагодження CSS у проектах з 10+ компонентами. Adoptable Stylesheets зменшують розмір бандла на 40–60% порівняно з вбудованими стилями.
Що входить у роботу з впровадження Shadow DOM?
- Аудит поточної CSS-архітектури та виявлення конфліктів.
- Проєктування компонентів з урахуванням дизайн-системи.
- Реалізація з підтримкою форм (ElementInternals), тематизації (CSS Custom Properties), стилізації (CSS Parts).
- Документація компонентів та гайд з використання.
- Тестування в різних браузерах, гарантія сумісності.
- Підтримка після впровадження: навчання команди, консультації.
Терміни: один компонент — до 1 дня, система з 5–8 компонентів — 1–2 тижні. Оцінимо ваш проект безкоштовно — просто напишіть нам. Отримайте консультацію щодо вашого проекту вже сьогодні. Замовте аудит CSS-архітектури безкоштовно.
Порада: як уникнути типових помилок
Перед впровадженням перевірте, чи підтримує ваша цільова аудиторія Shadow DOM (охоплення ~97% браузерів). Для старих браузерів використовуйте поліфіли. Не зловживайте ::part() — він порушує інкапсуляцію при частому використанні.







