Styling Integration
PAI Design를 앱의 theme, CSS, Tailwind 흐름에 연결하는 방법을 소개해요.
이 문서는 Getting started에서 첫 렌더를 마친 뒤, PAI Design을 실제 앱 스타일 구조에 어떻게 연결하면 좋은지 설명해요. 설치 순서보다 테마 연결 기준, CSS variable 사용 방식, Tailwind와의 연결 방법이 궁금할 때 읽으면 좋아요.
Overview
PAI Design를 앱에 연결할 때 핵심 기준은 아래 4가지예요.
| 항목 | 무엇을 하나요 | 기본 기준 |
|---|---|---|
@pai-design/react/styles.css | 토큰과 레시피 스타일을 한 번에 불러와요 | 앱 진입점에서 한 번만 import해요. |
.dark / .light class | 테마 토큰을 light / dark 모드에 맞게 바꿔요 | ThemeProvider 대신 class contract를 사용해요. |
| 앱 루트 font family | 컴포넌트가 상속할 기본 font를 정해요 | 컴포넌트 레시피는 inherit를 사용해 앱 font를 따라가요. |
@pai-design/tokens | custom UI와 layout에 토큰을 직접 연결해요 | 공개 컴포넌트가 없는 제품 전용 UI에서 사용해요. |
스타일 한 번만 불러오기
@pai-design/react를 사용한다면 앱 진입점에서 styles.css를 한 번만 import하면 돼요.
import "@pai-design/react/styles.css";여기에는 토큰 CSS variable과 레시피 스타일이 함께 들어 있어요. @pai-design/tokens/styles.css와 @pai-design/recipes/styles.css를 따로 나눠 불러올 필요는 없어요.
Theme 연결하기
PAI Design은 ThemeProvider를 제공하지 않아요. 대신 .dark와 .light class를 기준으로 토큰 값을 바꾸는 contract를 제공해요.
import "@pai-design/react/styles.css";
import { Button } from "@pai-design/react";
export function App() {
return (
<div className="dark">
<Button>저장하기</Button>
</div>
);
}보통은 html이나 앱 루트 컨테이너에 .dark를 두고, 화면 일부만 다른 theme로 보여주고 싶다면 특정 wrapper에만 .dark 또는 .light를 둘 수 있어요.
테마 상태를 어디에 저장하고 어떻게 토글할지는 앱이 맡아요. next-themes 같은 도구를 사용해 class만 일관되게 붙여주면 충분해요.
Font 연결하기
PAI Design 컴포넌트는 앱 font family를 상속해요. 시스템이 강제로 폰트를 덮어쓰지 않기 때문에, 제품 전체 font를 앱 루트에서 정하면 컴포넌트도 같은 기준을 따라가요.
공용 sans stack을 그대로 쓰고 싶다면 앱 루트에 아래처럼 둘 수 있어요.
html {
font-family: var(--pai-font-family-sans);
}별도 브랜드 폰트를 쓰고 있다면 앱 루트에서 그 font를 지정하면 돼요. 컴포넌트 레시피는 font-family: inherit를 사용하므로 추가 설정 없이 따라가요.
Token을 직접 사용하는 방법
공개 컴포넌트가 없는 제품 전용 UI나 layout shell은 @pai-design/tokens를 사용해 연결할 수 있어요.
import { tokenVars } from "@pai-design/tokens";
const panelStyle = {
background: tokenVars["color.bg.surface"],
maxWidth: tokenVars["size.surface.md"],
padding: tokenVars["space.4"],
};plain CSS에서는 생성된 CSS variable을 직접 사용할 수 있어요.
.panel {
background: var(--pai-color-bg-surface);
max-width: var(--pai-size-surface-md);
padding: var(--pai-space-4);
}역할이 이미 정해진 값이라면 raw px나 hex 값보다 semantic token을 먼저 사용해요.
Tailwind와 같이 쓸 때
PAI Design 자체는 Tailwind를 요구하지 않아요. plain CSS, CSS Modules, CSS-in-JS처럼 앱이 이미 쓰는 방식을 그대로 선택해도 괜찮아요.
앱이 Tailwind를 사용한다면, layout과 구조는 Tailwind utility로 두고 시각 값은 token CSS variable로 연결하는 방식이 가장 자연스러워요.
export function Panel({ children }: { children: React.ReactNode }) {
return (
<section className="bg-[var(--pai-color-bg-surface)] p-[var(--pai-space-4)]">
{children}
</section>
);
}이미 Button, Dialog처럼 공개 컴포넌트가 있는 경우에는 utility로 컴포넌트 핵심 위계를 다시 덮어쓰기보다, 먼저 제공된 public prop과 composition을 사용해요. Tailwind는 주변 layout과 page-specific composition에 쓰고, 컴포넌트 의미 자체는 시스템 contract를 따라가는 쪽이 더 안정적이에요.
무엇을 어디까지 시스템에 맡길지
- 반복되는 공통 UI는
@pai-design/react컴포넌트를 먼저 사용해요. - 제품 화면의 layout, section spacing, custom wrapper는
@pai-design/tokens로 연결해요. - theme 상태 저장과 토글은 앱이 맡고, 시스템은 class contract만 제공해요.
- 이미 컴포넌트가 가진 의미를 product utility로 다시 정의하지 않아요.
이 경계가 분명할수록 시스템은 작고 안정적으로 유지되고, 앱은 필요한 부분만 유연하게 확장할 수 있어요.
다음에 읽으면 좋은 문서
- token 구조와 layer 흐름은 Design Token에서 확인해요.
- 첫 import와 첫 렌더 흐름은 Getting started에서 확인해요.
- 색상과 spacing, typography 기준은 Foundation 문서에서 이어서 볼 수 있어요.