Shadow DOM, Tailwind, shadcn/ui 조합, 득보다 실이 많다!
Shadow DOM과 Tailwind CSS의 상반된 설계 철학으로 인해 스타일 적용에 문제 발생
shadcn/ui의 포탈(Portal) 컴포넌트가 Shadow DOM의 격리(Isolation)를 방해하여 스타일 미적용 문제 발생
CVA(Class Variance Authority)를 사용한 동적 클래스(Dynamic Class) 생성 시, Tailwind JIT 컴파일러(JIT Compiler)가 모든 클래스를 포함하지 못하는 문제 발생
Shadow DOM 환경에서 CSS 변수(Custom Properties) 상속이 제대로 이루어지지 않아 테마(Theme) 적용에 어려움
저자는 Shadow DOM 사용을 포기하고, CSS Modules 또는 Scoped Tailwind를 대안으로 제시
Shadow DOM과 Tailwind CSS의 근본적인 충돌
Tailwind CSS는 전역 스타일시트(Global Stylesheet)를 기반으로, 모든 요소에 유틸리티 클래스(Utility Class)를 적용하는 방식이다. 반면, Shadow DOM은 스타일 격리(Style Isolation)를 통해 외부 스타일의 침투를 막는다.
결과적으로 Shadow DOM 내부에서는 Tailwind CSS의 스타일이 적용되지 않아 컴포넌트가 깨져 보이는 현상 발생
해결책: 각 컴포넌트에서 Tailwind CSS를 직접 import해야 하지만, 번들 사이즈(Bundle Size) 증가 및 브라우저 캐싱(Browser Caching) 불가 등의 문제 발생
대안: CSS Modules 또는 Scoped Tailwind를 사용하여 스타일 충돌을 방지하고, Shadow DOM의 단점을 보완
shadcn/ui 포탈(Portal) 문제와 해결 방안
shadcn/ui는 Radix UI primitives를 기반으로 하며, Dialog, Dropdown, Popover, Tooltip과 같은 컴포넌트에서 React 포탈(React Portal)을 사용하여 DOM의 특정 위치에 렌더링한다.
Shadow DOM 환경에서 포탈로 렌더링된 컴포넌트는 Shadow DOM의 스타일 격리 경계를 벗어나 스타일이 적용되지 않는 문제 발생
해결책: Shadow DOM을 사용하지 않거나, 포탈을 사용하지 않는 컴포넌트만 선택적으로 사용하는 방법
포탈 사용 불가 시 UI 라이브러리(UI Library)의 기능 제약 발생
CVA(Class Variance Authority)와 Tailwind JIT 컴파일러(JIT Compiler)의 충돌
shadcn/ui는 CVA를 사용하여 컴포넌트의 다양한 스타일 변형을 관리하며, 이는 런타임(Runtime)에 Tailwind 클래스를 동적으로 생성한다.
Tailwind JIT 컴파일러는 빌드 시점에 사용된 클래스만 포함하므로, 런타임에 생성되는 클래스는 스타일이 적용되지 않는 문제 발생
해결책: 모든 가능한 클래스 조합을 safelist에 명시하여 강제로 포함시키는 방법
단점: CSS 번들 사이즈 증가, 수동 관리의 어려움, UI 라이브러리 변경 시 업데이트 필요
Shadow DOM 환경에서의 CSS 변수(Custom Properties) 문제
shadcn/ui는 테마(Theme)를 위해 CSS 변수를 사용하며, Shadow DOM은 CSS 변수의 상속을 막아 테마 적용을 어렵게 만든다.
Shadow DOM 내부에서 CSS 변수를 재정의해야 하며, 다크 모드(Dark Mode) 적용 시 추가적인 작업 필요
해결책: 각 컴포넌트에서 CSS 변수를 중복 정의하는 방법
단점: 테마 변수 중복, 테마 업데이트 시 여러 파일 수정 필요, 단일 소스(Single Source) 부재
Shadow DOM 사용의 트레이드오프(Trade-off)
Shadow DOM은 컴포넌트의 스타일 격리(Style Isolation)를 통해 캡슐화를 제공하지만, Tailwind CSS, shadcn/ui와 같은 현대적인 UI 개발 도구와의 통합에 어려움이 있다.
Shadow DOM 사용 시, 번들 사이즈 증가, 포탈 문제, CSS 변수 문제 등 다양한 문제 발생
대안: Shadow DOM을 선택적으로 사용하거나, CSS Modules, Scoped Tailwind와 같은 다른 기술을 활용하여 문제 해결
궁극적으로는 아키텍처적 순수성(Architectural Purity)보다 실제 작동하는 솔루션을 선택하는 것이 중요