Getting Started
Theming
라이트, 다크, 시스템 테마를 자동으로 지원하는 Vapor UI 테마 시스템을 설정하세요.이 문서에서는 Vapor UI의 테마 시스템 설정 방법을 설명합니다. ThemeProvider를 사용하여 라이트 모드, 다크 모드, 시스템 동기화를 구현할 수 있습니다.
설정
패키지 설치
npm install @vapor-ui/core@betaThemeProvider 설정
애플리케이션 최상위를 ThemeProvider로 감싸서 테마 시스템을 활성화합니다.
import { ThemeProvider } from '@vapor-ui/core';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ko" suppressHydrationWarning>
<body>
<ThemeProvider defaultTheme="system">{children}</ThemeProvider>
</body>
</html>
);
}SSR 환경에서는
suppressHydrationWarning을<html>태그에 추가하여 하이드레이션 경고를 방지합니다.
테마 제어
useTheme 훅으로 테마를 읽고 변경합니다. 아래는 테마 토글 버튼 구현 예제입니다.
'use client';
import { Button } from '@vapor-ui/components/ui/button';
import { useTheme } from '@vapor-ui/core';
export function ThemeToggle() {
const { resolvedTheme, setTheme, mounted } = useTheme();
// SSR 환경에서 hydration 완료 전까지 로딩 상태 표시
if (!mounted) {
return null;
}
return (
<Button
variant="ghost"
onClick={() => setTheme(resolvedTheme === 'light' ? 'dark' : 'light')}
>
{resolvedTheme === 'light' ? 'Dark' : 'Light'}
</Button>
);
}useTheme 훅 레퍼런스
useTheme 훅이 반환하는 값과 함수입니다.
| Key | Type | Description |
|---|---|---|
| theme | 'light' | 'dark' | 'system' | undefined | 현재 설정된 테마. SSR 환경에서 mounted가 false일 때는 undefined. |
| setTheme | (theme: 'light' | 'dark' | 'system' | ((prev: Theme) => Theme)) => void | 테마를 변경하는 함수. 함수형 업데이트도 지원하며 localStorage에 자동 저장됩니다. |
| themes | ('light' | 'dark' | 'system')[] | 사용 가능한 테마 목록. 항상 ['light', 'dark', 'system']을 포함합니다. |
| resolvedTheme | 'light' | 'dark' | undefined | 실제로 적용된 테마. theme가 'system'일 때 현재 시스템 테마를 반영합니다. |
| systemTheme | 'light' | 'dark' | undefined | 현재 사용자의 시스템 테마. theme가 'system'일 때만 제공됩니다. |
| forcedTheme | 'light' | 'dark' | 'system' | undefined | 강제로 적용된 테마. 설정되지 않았을 때는 undefined. |
| resetTheme | () => void | 테마 설정을 기본값으로 초기화하고 localStorage에서 저장된 값을 제거합니다. |
| mounted | boolean | ThemeProvider가 클라이언트에서 마운트되었는지 여부. SSR 환경에서 hydration 이슈 방지를 위해 사용. |
ThemeProvider 설정 옵션
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultTheme | 'light' | 'dark' | 'system' | 'system' | 테마 동작을 결정합니다. 'light', 'dark'는 고정 테마, 'system'은 시스템 테마에 자동 동기화됩니다. |
| storageKey | string | 'vapor-ui-theme' | localStorage에 테마를 저장할 때 사용될 키. |
| forcedTheme` | 'light' | 'dark' | 'system' | undefined | 특정 테마를 강제로 적용합니다. 이 값이 설정되면 다른 모든 테마 관련 설정을 무시합니다. |
| disableTransitionOnChange | boolean | false | true일 경우, 테마 변경 시 발생하는 CSS 트랜지션을 비활성화합니다. |
| enableColorScheme | boolean | true | true일 경우, color-scheme CSS 속성을 자동으로 설정하여 브라우저 UI(스크롤바 등)의 테마를 조정합니다. |
| nonce | string | undefined | undefined | CSP(Content Security Policy) nonce 값. 보안 정책이 적용된 환경에서 사용. |
부분 테마 적용
특정 영역에만 다른 테마를 적용하려면 ThemeScope를 사용합니다.
import { Card } from '@vapor-ui/components/ui/card';
import { ThemeScope } from '@vapor-ui/core';
export function ThemeScopeExample() {
return (
<div>
<Card>전역 테마가 적용된 카드</Card>
<ThemeScope forcedTheme="dark">
<Card>다크 테마가 강제 적용된 카드</Card>
</ThemeScope>
<ThemeScope forcedTheme="light">
<Card>라이트 테마가 강제 적용된 카드</Card>
</ThemeScope>
</div>
);
}Portal 컴포넌트와 함께 사용
Dialog, Popover 같은 Portal 컴포넌트가 ThemeScope의 테마를 상속받으려면 컨테이너를 지정합니다.
<ThemeScope forcedTheme="dark">
<section ref={sectionRef}>
{' '}
{/* 어떤 요소든 가능 */}
<Dialog.Content portalProps={{ container: sectionRef.current }}>
{/* 이 Portal은 다크 테마를 상속받음 */}
</Dialog.Content>
</section>
</ThemeScope>ThemeScope 옵션
| Prop | Type | Description |
|---|---|---|
| forcedTheme | 'light' | 'dark' | 해당 영역에 강제로 적용할 테마 |
| children | React.ReactNode | 테마가 적용될 자식 컴포넌트들 |
| style | CSSProperties | undefined | 추가 스타일 (colorScheme 자동 설정) |
고급 기능
SSR 처리
서버-클라이언트 테마 차이로 인한 hydration 오류를 자동으로 방지합니다.
mounted상태 추적: 클라이언트 마운트 완료 여부를 확인합니다.- 안전한 기본값: 마운트 전까지 충돌 없는 값을 사용합니다.
- 자동 동기화: 마운트 완료 후 실제 테마로 업데이트합니다.
테마 동작 모드
고정 테마 ('light' 또는 'dark')
- 지정된 테마로 고정됩니다.
- 시스템 테마 변경을 무시합니다.
- 사용자가 수동으로 변경할 수 있습니다.
시스템 동기화 ('system')
- 운영체제 테마 설정을 자동으로 감지합니다.
prefers-color-scheme미디어 쿼리로 실시간 추적합니다.- 시스템 변경 시 자동으로 업데이트됩니다.
우선순위
테마는 다음 순서로 적용됩니다.
forcedTheme: 강제 테마 (최우선)localStorage: 사용자가 선택한 테마defaultTheme: 기본 설정값
다중 탭 동기화
여러 브라우저 탭 간 테마 설정을 자동으로 동기화합니다. 한 탭에서 테마를 변경하면 같은 도메인의 다른 탭도 즉시 업데이트됩니다.
TypeScript 지원
import type { ThemeConfig, ThemeScopeProps, UseThemeProps } from '@vapor-ui/core';
// 시스템 테마에 자동 동기화
const systemConfig: ThemeConfig = {
defaultTheme: 'system',
};
// 라이트 테마로 고정
const lightConfig: ThemeConfig = {
defaultTheme: 'light',
};
const MyComponent = () => {
const themeData: UseThemeProps = useTheme();
// ...
};