한양과학기술고등학교

에듀테크 프로젝트 대시보드

Shadow DOM & 웹 컴포넌트

일반적인 HTML 요소(Light DOM)는 페이지 전역 CSS의 영향을 그대로 받습니다. 그런데 element.attachShadow()로 만든 Shadow DOM은 자기만의 독립된 미니 문서 트리를 가져서, 내부 스타일이 밖으로 새어나가지 않고 밖의 전역 스타일도 안으로 들어오지 않습니다. 이 캡슐화가 웹 컴포넌트(Web Components)의 핵심입니다.
🧪 스타일 캡슐화 실험 Light DOM vs Shadow DOM

아래 버튼을 누르면 "전역 CSS 규칙"이 페이지에 주입됩니다 (.badge-text { color: red !important; ... }). 두 배지는 똑같이 class="badge-text"를 갖고 있지만 결과는 다릅니다.

🔓 일반 <span> (Light DOM)
Hello Badge
🔒 <my-tag-badge> (Shadow DOM)
🌳 DOM 트리 구조
#document
<span class="badge-text"> ← 전역 CSS가 직접 스캔
<my-tag-badge> (호스트 엘리먼트)
#shadow-root (mode: open)
<style> .txt { ... } </style> ← 이 안에서만 유효
<span class="txt"> ← 전역 CSS 스캔 범위 밖
전역 querySelectorAll('*')이나 CSS 셀렉터는 shadow-root 경계 안쪽까지 들어가지 못합니다. 이것이 부트스트랩/테일윈드 같은 서드파티 CSS가 뒤섞여도 위젯이 깨지지 않는 원리입니다.
⚙️ 커스텀 엘리먼트 라이프사이클 실제 동작
// "엘리먼트 붙이기"를 눌러 실제 customElements 콜백을 확인하세요...
🕳️ <slot>으로 콘텐츠 투영하기

Shadow DOM은 안이 텅 비어있지 않습니다. <slot>이라는 "구멍"을 뚫어두면, 사용자가 태그 안에 넣은 Light DOM 자식이 그 구멍 자리에 그대로 비쳐서 보입니다 (실제로 이동하는 게 아니라 "투영"됩니다).

💻 이 페이지의 실제 웹 컴포넌트 코드
class MyTagBadge extends HTMLElement { constructor() { super(); const root = this.attachShadow({ mode: 'open' }); // 캡슐화 시작 root.innerHTML = ` <style> .txt { background:#b388ff22; color:#b388ff; padding:6px 12px; border-radius:999px; } </style> <span class="txt"><slot>기본 텍스트</slot></span> `; } connectedCallback() { // DOM에 삽입될 때 자동 호출 console.log('연결됨!'); } disconnectedCallback() { // DOM에서 제거될 때 자동 호출 console.log('제거됨!'); } static get observedAttributes() { return ['text']; } attributeChangedCallback(name, oldV, newV) { // 지정 속성 변경 시 자동 호출 this.shadowRoot.querySelector('.txt').textContent = newV; } } customElements.define('my-tag-badge', MyTagBadge); // 새 HTML 태그 등록! // 이제 HTML 어디서든 <my-tag-badge text="Hi"></my-tag-badge> 처럼 그냥 태그로 쓸 수 있음
React의 Virtual DOM과는 다른 개념입니다. Virtual DOM은 "어떻게 빠르게 다시 그릴까"에 대한 렌더링 최적화 기법이고, Shadow DOM은 "어떻게 스타일/마크업을 다른 코드로부터 격리할까"에 대한 브라우저 네이티브 캡슐화 기능입니다. 실제로 <video>, <input type="range"> 같은 브라우저 내장 태그들도 내부적으로 Shadow DOM으로 구현되어 있어서, 우리가 그 복잡한 내부 구조를 몰라도 태그 하나로 쓸 수 있는 것입니다.