@seoku/design-system
v1.1.15
Published
Seoku Design System
Readme
@seoku/design-system
Seoku Design System — React + Tailwind CSS v4로 빌드된 컴포넌트 라이브러리.
라이브러리 자체는 Tailwind v4로 빌드되지만, 소비 프로젝트는 Tailwind v4일 필요가 없습니다. Tailwind v2/v3, 또는 Tailwind를 아예 쓰지 않는 순수 CSS/SCSS 프로젝트에서도 동일하게 안전하게 사용할 수 있습니다. 자세한 내용은 스타일 오버라이드 우선순위 참고.
설치
pnpm add @seoku/design-system필수 설정
⚠️ 이 단계를 빠뜨리면 컴포넌트 스타일이 깨집니다.
1. CSS 설정
프로젝트의 전역 CSS 파일(globals.css 등)에 아래 순서대로 import하세요.
/* globals.css */
@import "@seoku/design-system/tokens.css"; /* 디자인 토큰 (CSS 변수) */
@import "@seoku/design-system/tailwind-theme.css"; /* Tailwind 유틸리티 자동완성 활성화 */
@import "@seoku/design-system/styles"; /* 컴포넌트 스타일 번들 */
@import "tailwindcss"; /* preflight (base reset) */⚠️
tailwindcssimport를 빠뜨리면 브라우저 기본 스타일이 초기화되지 않아 레이아웃이 틀어집니다.⚠️ 이 순서(SDS 먼저, 프로젝트 자체 CSS는 나중)를 지키세요. preflight 문제뿐 아니라, 커스텀 CSS/SCSS 클래스로 SDS를 오버라이드할 때도 이 순서가 오버라이드 성공 여부를 좌우합니다 — 자세한 내용은 스타일 오버라이드 우선순위 참고.
2. Tailwind CSS v4 설치
pnpm add -D tailwindcss @tailwindcss/postcsspostcss.config.mjs:
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};컴포넌트 사용
import { Button } from "@seoku/design-system";
export function Example() {
return <Button variant="primary">클릭</Button>;
}className prop으로 커스터마이징
컴포넌트는 className prop을 받아 소비자 프로젝트의 Tailwind 클래스를 병합합니다.
소비자 코드에서는 sds: prefix 없이 본인 프로젝트의 일반 Tailwind 유틸리티를 사용합니다.
// 소비자 프로젝트 (본인 Tailwind로 작성)
<Button className="w-full mt-4">전체 너비 버튼</Button>
<Avatar className="ring-2 ring-primary-500" />내부 구조 참고: 디자인 시스템의 컴포넌트 내부 클래스는
sds:prefix가 붙습니다(sds:flex,sds:rounded-full등). 이는 소비자 Tailwind 스코프와 충돌을 방지하기 위한 네임스페이스입니다. 컴포넌트를 사용할 때는 이 prefix를 신경 쓸 필요가 없습니다.
스타일 오버라이드 우선순위
SDS 컴포넌트의 기본 스타일은 항상 안전하게 유지되면서도, 소비 프로젝트가 원하면 얼마든지 덮어쓸 수 있도록 설계되어 있습니다. Tailwind v2/v3/v4, 또는 Tailwind를 아예 쓰지 않는 순수 CSS/SCSS 프로젝트 모두 동일하게 적용됩니다 — 버전별 별도 설정이 필요 없습니다.
SDS 기본 스타일이 안 깨지는 이유
SDS는 CSS를 네이티브 @layer로 감싸지 않고 unlayered로 출고합니다. 컴포넌트 클래스는 전부 단일 클래스 셀렉터(specificity 0,1,0)인 반면, 브라우저 기본 스타일이나 Tailwind preflight 리셋은 보통 태그 셀렉터(specificity 0,0,1)입니다. SDS가 항상 더 높은 specificity를 가지므로 별도 설정 없이도 preflight에 깨지지 않습니다. 이건 CSS 명세 자체의 규칙이라 Tailwind 버전과 무관하게 항상 성립합니다.
참고로 SDS 클래스를 named layer(
@layer sds-components등)로 감싸는 방식도 검토했었지만, Tailwind v2/v3 및 Tailwind 미사용 프로젝트는 애초에 native@layer를 쓰지 않기 때문에 — "unlayered가 layered를 무조건 이긴다"는 cascade 규칙상 — 오히려 SDS 기본 스타일이 호스트의 아무 CSS에나 깨지는 문제가 생겨 채택하지 않았습니다.
오버라이드 방법 1 — className prop + Tailwind 유틸리티 (권장)
Tailwind 유틸리티 클래스 문법으로 오버라이드하면 import 순서와 무관하게 항상 이깁니다.
<Button className="rounded-2xl" /> {/* SDS 기본값 rounded-lg를 항상 덮어씀 */}컴포넌트 내부의 cn()이 sds: 접두사를 벗겨 표준 Tailwind 클래스명으로 변환한 뒤 충돌 여부를 판단하고, 충돌하는 SDS 내부 클래스를 JS 레벨에서 DOM에 렌더링되기 전에 제거합니다. CSS cascade에 전혀 기대지 않는 결정적(deterministic) 동작이라 Tailwind v2/v3/v4 어디서든 동일하게 작동합니다.
오버라이드 방법 2 — 커스텀 CSS/SCSS 클래스
Tailwind 유틸리티 문법이 아닌, 직접 정의한 클래스명으로 오버라이드하는 경우(cn()이 인식할 수 없는 임의 클래스)에는 SDS 내부 클래스가 DOM에서 제거되지 않고 그대로 남습니다. 이 경우 두 클래스의 specificity가 동률(0,1,0 vs 0,1,0)이라 CSS 소스 순서(나중에 로드된 쪽이 이김) 로 결정됩니다:
// 소비 프로젝트 SCSS
.my-button { border-radius: 4px; }<Button className="my-button" />이 경우 이기려면 아래 중 하나를 지키세요.
- 필수 설정에서 안내한 순서대로 SDS CSS를 프로젝트 자체 글로벌 CSS보다 먼저 import하세요. 프로젝트 자체 CSS가 항상 나중에 로드되어 이깁니다.
- 순서를 보장하기 어렵다면 selector specificity를 SDS보다 높이세요 (부모 스코프 추가 등 — 순서와 무관하게 항상 이김):
// specificity (0,1,0) — import 순서에 의존
.my-button { border-radius: 4px; }
// specificity (0,2,0) — 순서 무관하게 항상 이김
.my-app .my-button { border-radius: 4px; }!important도 동작하지만, 유지보수성을 위해 specificity를 높이는 방법을 권장합니다.
요약
| 오버라이드 방식 | 보장 수준 |
|---|---|
| className="rounded-2xl" (Tailwind 유틸리티 문법) | import 순서 무관, 항상 이김 |
| 커스텀 CSS/SCSS 클래스 (기본) | import 순서를 지켜야 이김 |
| 커스텀 CSS/SCSS 클래스 + specificity 상향 또는 !important | import 순서 무관, 항상 이김 |
CSS 파일 가이드
| 파일 | 내용 | 필수 여부 |
|------|------|-----------|
| tokens.css | CSS 변수 전체 (--sds-* 네임스페이스) | 필수 |
| tailwind-theme.css | --sds-* 변수를 Tailwind 유틸리티로 노출 (bg-surface-*, text-content-* 등) | Tailwind 사용 시 권장 |
| styles | 컴포넌트 스타일 번들 (유틸리티 포함) | 필수 |
시나리오 A — Tailwind CSS v4 프로젝트 (권장)
@import "@seoku/design-system/tokens.css";
@import "@seoku/design-system/tailwind-theme.css";
@import "@seoku/design-system/styles";
@import "tailwindcss";tailwind-theme.css를 포함하면 소비자 코드에서 bg-surface-muted, text-content-subtle, border-line-strong 같은 디자인 토큰을 Tailwind 유틸리티로 직접 쓸 수 있고, Tailwind CSS IntelliSense 자동완성도 동작합니다.
시나리오 B — Tailwind 없이 컴포넌트만 사용
@import "@seoku/design-system/tokens.css";
@import "@seoku/design-system/styles";컴포넌트 스타일은 정상 동작하지만, 소비자 코드에서 Tailwind 유틸리티 클래스를 사용할 수 없습니다.
시나리오 C — CSS 변수(토큰)만 참조
@import "@seoku/design-system/tokens.css";또는 JS에서 직접:
import { colors, spacing, shadows } from "@seoku/design-system/tokens";
const primary = colors.primary[500]; // '#00c4a1'
const gap = spacing.m; // '16px'CSS 변수 직접 사용
tokens.css는 --sds-* 네임스페이스로 모든 디자인 토큰을 정의합니다.
.my-element {
color: var(--sds-text-default);
background: var(--sds-bg-default);
border: 1px solid var(--sds-border-default);
border-radius: var(--radius-md);
}주요 CSS 변수:
| 카테고리 | 변수 예시 |
|---|---|
| 색상 (팔레트) | --sds-primary-500, --sds-neutral-600, --sds-danger-500 |
| 색상 (시맨틱) | --sds-bg-default, --sds-text-default, --sds-border-default |
| 폰트 | --sds-fontfamily-base |
| 반경 | --radius-xs ~ --radius-3xl, --radius-full |
| 간격 | --spacing-xxxs ~ --spacing-xxxxxl |
| 그림자 | --shadow-sm ~ --shadow-modal |
| 전환 | --duration-fast ~ --duration-slower |
다크 모드
data-theme="dark" 속성 또는 prefers-color-scheme: dark 미디어쿼리로 자동 전환됩니다.
<!-- 수동 다크 모드 -->
<html data-theme="dark">...</html>
<!-- 라이트 모드 고정 -->
<html data-theme="light">...</html>토큰 오버라이드
CSS 변수를 덮어써서 색상이나 기타 값을 프로젝트에 맞게 변경할 수 있습니다.
패턴 A — 시맨틱 토큰만 교체 (권장)
컴포넌트가 참조하는 시맨틱 토큰만 바꾸는 방식. 영향 범위가 명확합니다.
@import "@seoku/design-system/tokens.css";
@import "@seoku/design-system/styles";
@import "tailwindcss";
/* 버튼·링크 등 주요 인터랙션 색상만 교체 */
:root {
--sds-action-primary: #7c3aed;
--sds-action-primary-hover: #6d28d9;
}패턴 B — 원시 토큰 교체 (브랜드 컬러 전체 교체)
원시 토큰을 바꾸면 해당 색상을 참조하는 시맨틱 토큰 전체에 영향을 줍니다.
:root {
--sds-primary-500: #7c3aed;
--sds-primary-600: #6d28d9;
--sds-action-primary: var(--sds-primary-500);
--sds-action-primary-hover: var(--sds-primary-600);
}패턴 C — 특정 영역에만 스코프 오버라이드
전역이 아닌 특정 컨테이너 내부에서만 다른 값을 적용할 수 있습니다.
/* 어드민 패널 영역만 다른 accent 색상 */
.admin-panel {
--sds-action-primary: #dc2626;
--sds-action-primary-hover: #b91c1c;
}폰트 교체
기본 폰트(Pretendard, Inter)를 프로젝트 폰트로 교체하려면:
:root {
--sds-fontfamily-base: 'MyCustomFont', sans-serif;
}