Getting Started

Theming

라이트, 다크, 시스템 테마를 자동으로 지원하는 Vapor UI 테마 시스템을 설정하세요.

Vapor UI는 라이트 모드, 다크 모드, 시스템 동기화를 자동으로 지원합니다. ThemeProvider 하나로 완전한 테마 관리 시스템을 구축할 수 있습니다.

빠른 설정

패키지 설치

npm install @vapor-ui/core@beta

ThemeProvider 설정

애플리케이션 최상위를 ThemeProvider로 감싸면 테마 시스템이 활성화됩니다:

app/layout.tsx
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 훅으로 테마를 읽고 변경할 수 있습니다. 다음 예제는 테마 토글 버튼 구현 방법입니다:

components/theme-toggle.tsx
'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 훅 레퍼런스

테마 관리에 필요한 모든 기능을 제공합니다:

KeyTypeDescription
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에서 저장된 값을 제거합니다.
mountedbooleanThemeProvider가 클라이언트에서 마운트되었는지 여부. SSR 환경에서 hydration 이슈 방지를 위해 사용.

ThemeProvider 설정 옵션

PropTypeDefaultDescription
defaultTheme'light' | 'dark' | 'system''system'테마 동작을 결정합니다. 'light', 'dark'는 고정 테마, 'system'은 시스템 테마에 자동 동기화됩니다.
storageKeystring'vapor-ui-theme'localStorage에 테마를 저장할 때 사용될 키.
forcedTheme`'light' | 'dark' | 'system'undefined특정 테마를 강제로 적용합니다. 이 값이 설정되면 다른 모든 테마 관련 설정을 무시합니다.
disableTransitionOnChangebooleanfalsetrue일 경우, 테마 변경 시 발생하는 CSS 트랜지션을 비활성화합니다.
enableColorSchemebooleantruetrue일 경우, color-scheme CSS 속성을 자동으로 설정하여 브라우저 UI(스크롤바 등)의 테마를 조정합니다.
noncestring | undefinedundefinedCSP(Content Security Policy) nonce 값. 보안 정책이 적용된 환경에서 사용.

부분 테마 적용 (ThemeScope)

특정 영역에만 다른 테마를 적용하고 싶을 때 ThemeScope를 사용합니다:

components/theme-scope-example.tsx
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 옵션

PropTypeDescription
forcedTheme'light' | 'dark'해당 영역에 강제로 적용할 테마
childrenReact.ReactNode테마가 적용될 자식 컴포넌트들
styleCSSProperties | undefined추가 스타일 (colorScheme 자동 설정)

고급 기능

SSR 자동 처리

서버-클라이언트 테마 차이로 인한 hydration 오류를 자동으로 방지합니다:

  • mounted 상태 추적: 클라이언트 마운트 완료 여부 확인
  • 안전한 기본값: 마운트 전까지 충돌 없는 값 사용
  • 자동 동기화: 마운트 완료 후 실제 테마로 업데이트

테마 동작 모드

고정 테마 ('light' 또는 'dark'):

  • 지정된 테마로 고정
  • 시스템 테마 변경 무시
  • 사용자가 수동으로 변경 가능

시스템 동기화 ('system'):

  • 운영체제 테마 설정 자동 감지
  • prefers-color-scheme 미디어 쿼리로 실시간 추적
  • 시스템 변경 시 자동 업데이트

우선순위 시스템

  1. forcedTheme - 강제 테마 (최우선)
  2. localStorage - 사용자 선택 (사용자 존중)
  3. 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();
    // ...
};