← Назад к вопросам

Есть ли Shadow DOM в React?

2.0 Middle🔥 141 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Есть ли Shadow DOM в React?

React и Shadow DOM — это две разные технологии на разных уровнях абстракции. React работает с Virtual DOM, а Shadow DOM — это стандарт Web Components. Расскажу про их взаимодействие.

Что такое Shadow DOM?

Shadow DOM (Теневой DOM) — это стандарт Web Components, который позволяет создавать инкапсулированное дерево элементов, изолированное от основного DOM.

// Создание Shadow DOM
const hostElement = document.getElementById('host');
const shadowRoot = hostElement.attachShadow({ mode: 'open' });

shadowRoot.innerHTML = `
  <style>
    /* Стили изолированы внутри Shadow DOM */
    p { color: red; }
  </style>
  <p>Это текст в Shadow DOM</p>
`;

Разница между Virtual DOM (React) и Shadow DOM

АспектVirtual DOM (React)Shadow DOM
Что это?Копия реального DOM в памятиИнкапсулированное дерево элементов
ЦельОптимизация обновленийИнкапсуляция стилей и структуры
Видно в DevTools?Нет (только JavaScript объект)Да (отдельное дерево)
Изоляция стилейНет (нужно использовать BEM, CSS-in-JS)Да (встроенная)
Стандарт браузераРеализовано в ReactДа, стандарт W3C
СовместимостьРаботает вездеНе поддерживается IE11

React и Shadow DOM

React НЕ использует Shadow DOM по умолчанию, но можно создавать Web Components с Shadow DOM и использовать их в React.

Создание Web Component с Shadow DOM

// Классический Web Component с Shadow DOM
class MyComponent extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });
    
    shadow.innerHTML = `
      <style>
        :host {
          display: block;
          padding: 10px;
          border: 1px solid #ccc;
        }
        
        p {
          color: blue;
          margin: 0;
        }
      </style>
      <p>Компонент с Shadow DOM</p>
    `;
  }
}

customElements.define('my-component', MyComponent);
<!-- Использование в HTML -->
<my-component></my-component>

Использование Web Component в React

// React компонент, использующий Web Component с Shadow DOM
function App() {
  return (
    <div>
      {/* Web Component работает в React как обычный HTML элемент */}
      <my-component></my-component>
    </div>
  );
}

Передача свойств и атрибутов

// Web Component (с Shadow DOM)
class MyButton extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });
    shadow.innerHTML = `
      <style>
        button {
          background: ${this.getAttribute('color') || 'blue'};
          color: white;
          padding: 10px 20px;
        }
      </style>
      <button><slot></slot></button>
    `;
  }
}

customElements.define('my-button', MyButton);
// Использование в React
function App() {
  return (
    <>
      {/* Атрибуты передаются как на обычный HTML элемент */}
      <my-button color="red">Нажми</my-button>
      <my-button color="green">Нажми</my-button>
    </>
  );
}

Слоты (Slots) в Shadow DOM

Slot — это плейсхолдер в Shadow DOM для вставки содержимого.

class Card extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });
    shadow.innerHTML = `
      <style>
        .card {
          border: 1px solid #ddd;
          padding: 20px;
          border-radius: 8px;
        }
      </style>
      <div class="card">
        <h2><slot name="title"></slot></h2>
        <p><slot name="content"></slot></p>
        <footer><slot name="footer"></slot></footer>
      </div>
    `;
  }
}

customElements.define('my-card', Card);
// Использование со слотами
function App() {
  return (
    <my-card>
      <h3 slot="title">Заголовок</h3>
      <p slot="content">Основной контент</p>
      <span slot="footer">Подвал</span>
    </my-card>
  );
}

Можно ли сделать Shadow DOM в React компонентах?

// Да, можно создать React компонент с Shadow DOM
import { useEffect, useRef } from 'react';

function MyReactComponent() {
  const divRef = useRef(null);
  
  useEffect(() => {
    if (divRef.current && !divRef.current.shadowRoot) {
      const shadow = divRef.current.attachShadow({ mode: 'open' });
      shadow.innerHTML = `
        <style>
          p { color: red; }
        </style>
        <p>Текст в Shadow DOM</p>
      `;
    }
  }, []);
  
  return <div ref={divRef}></div>;
}

Проблемы React с Shadow DOM

1. React не может управлять содержимым Shadow DOM

function App() {
  const [text, setText] = useState('Привет');
  const divRef = useRef(null);
  
  useEffect(() => {
    const shadow = divRef.current.attachShadow({ mode: 'open' });
    shadow.innerHTML = `<p>${text}</p>`; // React НЕ обновляет это!
  }, [text]); // Зависимость text не помогает
  
  return (
    <>
      <div ref={divRef}></div>
      <button onClick={() => setText('Пока')}>Изменить</button>
    </>
  );
}

2. Портали (Portals) работают лучше

import { createPortal } from 'react-dom';

function App() {
  const [text, setText] = useState('Привет');
  const divRef = useRef(null);
  
  useEffect(() => {
    divRef.current.attachShadow({ mode: 'open' });
  }, []);
  
  return (
    <>
      <div ref={divRef}>
        {/* React может управлять этим содержимым через портал */}
        {createPortal(
          <p style={{ color: 'red' }}>{text}</p>,
          divRef.current.shadowRoot
        )}
      </div>
      <button onClick={() => setText('Пока')}>Изменить</button>
    </>
  );
}

Когда использовать Shadow DOM?

Плюсы:

  • Инкапсуляция стилей (CSS не влияет друг на друга)
  • Скрытие сложной реализации
  • Web Components переиспользуются везде

Минусы:

  • Сложность с React
  • Проблемы с контролем содержимого
  • Пересекающиеся стили сложнее дебагить

Практический пример: Web Component с Shadow DOM в React

// components/Modal.js
class Modal extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
  }
  
  connectedCallback() {
    this.shadowRoot.innerHTML = `
      <style>
        :host {
          --modal-bg: white;
        }
        .modal {
          background: var(--modal-bg);
          padding: 20px;
          border-radius: 8px;
          box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
      </style>
      <div class="modal">
        <slot></slot>
      </div>
    `;
  }
}

customElements.define('custom-modal', Modal);
// App.jsx
function App() {
  return (
    <custom-modal>
      <h2>Заголовок модали</h2>
      <p>Содержимое модали</p>
    </custom-modal>
  );
}

Ключевые моменты

  • React использует Virtual DOM, НЕ Shadow DOM
  • Shadow DOM — это стандарт для Web Components (инкапсуляция)
  • Можно создавать Web Components с Shadow DOM и использовать в React
  • React не может управлять содержимым Shadow DOM напрямую
  • Для хорошей интеграции с React нужны Portals и useRef
  • Shadow DOM полезен для переиспользуемых компонентов с изолированными стилями