이 문서의 역할
이 글은 특정 화면을 고치는 절차가 아니라 구조가 필요한 이유를 다루는 설명 문서임
Tailwind CSS를 쓰는 화면이 커지면 긴 className이 가장 먼저 눈에 들어온다. 그러나 class 문자열의 길이는 변경 비용을 직접 설명하지 못한다. 실제 비용은 같은 시각 결정을 몇 군데에서 다시 내려야 하는지, 어느 계층을 고쳐야 하는지 예측할 수 있는지, 변경이 접근성과 제품 동작에 어떤 영향을 주는지에서 발생한다.
문제는 class 수가 아니라 결정의 중복임
bg-white dark:bg-gray-950을 열 곳에서 사용하면 각 호출부가 theme 결정을 소유한다. 문자열을 CSS class 하나로 숨겨도 전역 selector와 cascade가 그 결정을 대신 소유할 뿐이다. 반대로 긴 utility 목록도 한 primitive가 상태, focus와 간격을 함께 관리한다면 변경 위치는 하나로 유지된다.
유지보수 가능한 구조는 "이 값을 어디에 둘 것인가"보다 "누가 이 결정을 바꿀 권한을 갖는가"에 답한다.
| 변경 질문 | 변경 owner | 영향 |
|---|---|---|
| light·dark 실제 색이 바뀌는가 | theme provider | 같은 semantic role을 쓰는 모든 UI |
| 공개할 semantic utility가 바뀌는가 | token adapter | Tailwind가 생성하는 API |
| focus·ARIA·범용 시각 상태가 바뀌는가 | shared primitive | 모든 제품 consumer |
| 업무 문구와 상태 연결이 바뀌는가 | product composition | 해당 제품 흐름 |
| grid와 responsive placement가 바뀌는가 | page·feature | 해당 화면 배치 |
semantic token은 값이 아니라 변경 경계임
primary는 특정 초록색의 별명이 아니라 주 동작이라는 역할이다. 호출부가 bg-primary text-primary-foreground를 사용하면 light·dark 실제 값은 provider로 이동하고, foreground pair와 contrast는 theme 계약에서 함께 검토할 수 있다.
raw palette를 금지하는 목적도 색상 취향을 통제하는 데 있지 않다. 제품 전체의 의미 변화가 page별 색상 교체 작업으로 번지는 것을 막는 데 있다. chart renderer처럼 CSS variable을 쓸 수 없는 경계는 예외로 남기되 owner와 이유를 기록해야 같은 원칙이 유지된다.
shadcn/ui는 라이브러리보다 source 공급자에 가까움
shadcn/ui component는 설치 후 저장소가 소유한다. 이 모델은 제품에 맞는 variant와 접근성 보정을 허용하지만 upstream을 무조건 덮어쓸 수 없게 만든다.
따라서 update의 핵심은 버전을 올리는 일이 아니라 세 종류의 변경을 구분하는 일이다.
- upstream의 접근성·API 개선은 local source에 병합해야 함
- 제품에 맞춘 variant와 token 연결은 local 정책으로 보존해야 함
- 생성 전용 계층이 아니라면
--overwrite가 local 판단을 제거할 수 있음
공용 primitive는 anti-corruption layer로 동작함
앱이 Base UI나 registry 세부 구현에 직접 의존하면 headless library의 API 변화가 제품 코드 전체로 퍼진다. @jongminchung/ui 같은 공용 계층은 접근성, 상태와 범용 variant를 한 번 해석하고 앱에는 안정된 primitive API를 제공한다.
이 경계가 유효하려면 공용 계층은 제품 이름을 몰라야 한다. destructive는 범용 intent이지만 repository-danger나 checkout-warning은 제품 의미다. 여러 앱에서 모양이 같아도 변경 이유가 다르면 서로 다른 composition으로 남는 편이 안전하다.
검증은 계층과 같은 방향으로 확장됨
page layout은 formatter, typecheck와 대표 viewport로 확인할 수 있다. 공용 token이나 primitive를 바꾸면 영향이 여러 앱으로 확장되므로 package test, consumer build, keyboard interaction과 light·dark visual까지 검증 범위를 넓혀야 한다.
이 방식은 모든 변경에 최대 검사를 요구하지 않는다. 변경 owner가 넓을수록 증명 범위도 넓어진다는 대응 관계를 만든다.
다음 목적에 맞는 문서로 이동함
결론
Tailwind와 shadcn/ui의 유지보수성은 utility를 감추는 기법보다 변경 권한을 theme, primitive, composition과 page로 분리하는 구조에서 나옴. 이 구조가 있으면 새 요구가 들어왔을 때 수정 위치와 검증 범위를 함께 예측할 수 있음