-
Shadow DOM이란 ? ❔❓웹 개발 2026. 2. 16. 00:28
프론트엔드 개발하다 보면 가끔 이런 경험을 한다.
- DOM에는 분명히 버튼이 보이는데 querySelector가 안 된다
- CSS를 아무리 써도 스타일이 안 먹는다
- DevTools에는 있는데 코드로는 접근이 안 된다
이런 경우엔, Shadow DOM을 의심해볼 수 있다.
Shadow DOM이란? 👻
Shadow DOM은 간단히 말하면
DOM 안에 또 하나의 “격리된 DOM 트리”를 만드는 기술
이다.
일반적인 DOM 구조가 이런 식이라면
<div id="app"> <button>Click</button> </div>Shadow DOM을 쓰면 이렇게 된다
<my-button> #shadow-root <button>Click</button> </my-button>중요한 포인트는 다음과 같다
- #shadow-root 내부는 외부 DOM과 격리
- CSS, JS 접근 모두 기본적으로 차단
- 캡슐화된 컴포넌트를 만들기 위한 구조
왜 굳이 이런 걸 만들었을까? 🤔
문제는 “전역 DOM & 전역 CSS”였다
웹은 기본적으로 다음과 같은 성질이 있다
- DOM => 전역
- CSS => 전역
- 따라서, 클래스 이름 충돌이 발생할 가능성이 높다
.button { background: red; }이 스타일은 라이브러리든, 앱 코드든, 어디든 다 먹는다.
➡️ 규모 커질수록 충돌 + 사이드 이펙트 발생할 가능성이 높다
Shadow DOM의 목적 🎯
Shadow DOM은 이 문제를 해결한다.
- DOM 구조 캡슐화
- CSS 완전 격리
- 컴포넌트 단위 재사용 가능
즉,
“이 컴포넌트 안에서는 외부의 내용이 적용되지 않는다”
를 가능하게 해준다.
실제로 어떻게 쓰나?
1️⃣ Shadow Root 생성
const host = document.querySelector("#host"); const shadow = host.attachShadow({ mode: "open" });- mode: "open" → JS로 접근 가능
- mode: "closed" → 외부 접근 완전 차단
2️⃣ Shadow DOM에 마크업 삽입
shadow.innerHTML = ` <style> button { background: black; color: white; } </style> <button>Shadow Button</button> `;이제 이 버튼은
- 외부 CSS 영향 ❌
- 외부 JS 접근 ❌ (querySelector 안 됨)
진짜 중요한 포인트들 ⚠️
1️⃣ querySelector가 안 되는 이유
document.querySelector("button"); // nullShadow DOM은 DOM 트리 탐색 대상이 아님.
접근하려면 다음과 같이 해야함
host.shadowRoot.querySelector("button");이렇게 명시적으로 들어가야 함.
2️⃣ CSS도 기본적으로 안 먹는다
button { border-radius: 8px; }➡️ Shadow DOM 안의 버튼엔 적용 ❌
3️⃣ 그래도 통로는 있다: ::part, ::slotted
Shadow DOM이 완전 폐쇄는 아니다.
::part
<button part="btn">Click</button>my-button::part(btn) { background: red; }::slotted
<slot></slot>::slotted(span) { color: blue; }➡️ 의도적으로 열어준 부분만 스타일링 가능
그래서 이걸 언제 사용할까 ?
사실 이미 매일 쓰고 있다 😅
- <video>
- <input type="range">
- <select>
- <details>
이런 브라우저 기본 컴포넌트들 전부 Shadow DOM 기반이다.
UI 라이브러리에서도 등장
- Web Components 기반 라이브러리
- Custom Elements
- 일부 Design System
그리고 DevTools에서 보면
#shadow-root (open)이거 보이면 거의 확정이다.
Shadow DOM의 장단점 정리 🧠
👍 장점
- 완벽한 캡슐화
- CSS 충돌 없음
- 컴포넌트 재사용성 극대화
- 라이브러리 간 안전한 공존
👎 단점
- 디버깅 난이도 상승
- DOM 접근 로직 복잡
- CSS 커스터마이징 제한
- 러닝 커브 존재
요즘 UI 라이브러리들은 다음과 같은 구조를 사용한다고 하기도 한다.
- 내부는 Shadow DOM
- 외부는 part, theme token 등으로 제어
이런 절충안을 많이 쓴다고 함.
마무리
Shadow DOM은
“DOM을 숨기는 기술”이 아니라
“컴포넌트를 지키는 기술”이다.
이걸 이해하면
- 왜 스타일이 안 먹는지
- 왜 선택자가 안 잡히는지
- 왜 라이브러리들이 이렇게 만드는지
전부 납득이 된다.
# 참고자료 👽
https://developer.mozilla.org/ko/docs/Web/API/Web_components/Using_shadow_DOM
shadow DOM 사용하기 - Web API | MDN
이 문서는 여러분이 이미 DOM (Document Object Model)의 개념에 익숙하다고 가정합니다. DOM이란 마크업 문서에서 나타나는 여러 가지 요소들과 텍스트 문자열을 나타내는 연결된 노드들의 트리같은 구
developer.mozilla.org
https://ui.toast.com/posts/ko_20170721
웹 컴포넌트(3) - 쉐도우 돔(#Shadow DOM)
이 글은 웹 컴포넌트 소개 연재로 그중 세 번째인 쉐도우 돔에 대한 글이다. 아마도 이전 글의 커스텀 엘리먼트 글을 읽고 온 분은 여러 스펙, API, 기억해 두어야 할 것들로 질렸을지도 모르겠다.
ui.toast.com
https://saramin.github.io/2025-11-12-shadow-dom/
Shadow Dom : 중요한 건 깨지지 않는 스타일
하나의 서비스에서 다양한 플랫폼의 이력서를 깨지지 않고 보여주는 방법
saramin.github.io
'웹 개발' 카테고리의 다른 글
Element.setHTML()이란 ?? (0) 2025.12.21 Chrome dev tools mcp 사용해보기 🍪 (0) 2025.12.13 가상호스트(Virtual Host)란 무엇인가? (0) 2025.12.05 MIME 타입(Multipurpose Internet Mail Extensions) 정리 🎩 (0) 2025.10.31 웹 브라우저에 데이터를 저장하고 싶다면? IndexedDB 톺아보기 🖥️ (0) 2025.09.29