블로그 목록으로
튜토리얼

Tailwind CSS로 디자인 시스템 구축하기

tailwindcssdesign-systemcss

디자인 시스템은 프로젝트의 시각적 일관성을 유지하고 개발 속도를 높이는 핵심 기반입니다. Tailwind CSS는 유틸리티 퍼스트 접근 방식 덕분에 디자인 시스템을 구축하기에 매우 적합한 도구입니다. 이 글에서는 디자인 토큰 정의부터 컴포넌트 패턴까지, 실제 프로젝트에 바로 적용할 수 있는 방법론을 공유합니다.

디자인 토큰: 시스템의 기초

디자인 토큰은 색상, 간격, 타이포그래피 등 디자인의 기본 단위를 추상화한 값입니다. Tailwind CSS 설정 파일에서 이를 체계적으로 정의합니다.

색상 토큰

색상은 디자인 시스템에서 가장 중요한 토큰입니다. 구체적인 색상 값이 아닌 의미(semantic) 기반으로 정의하는 것이 핵심입니다.

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        // 브랜드 색상
        brand: {
          50: '#f0f4ff',
          100: '#dbe4ff',
          500: '#4c6ef5',
          600: '#3b5bdb',
          700: '#364fc7',
        },
        // 시맨틱 색상
        surface: {
          DEFAULT: '#ffffff',
          secondary: '#f8f9fa',
          tertiary: '#f1f3f5',
        },
        content: {
          DEFAULT: '#212529',
          secondary: '#495057',
          tertiary: '#868e96',
        },
        border: {
          DEFAULT: '#dee2e6',
          strong: '#adb5bd',
        },
      },
    },
  },
};

surface, content, border처럼 용도 기반으로 이름을 짓으면, 다크 모드 전환 시 값만 바꾸면 되므로 유지보수가 훨씬 쉬워집니다.

간격과 타이포그래피

일관된 간격 체계는 디자인의 리듬감을 만들어줍니다. Tailwind의 기본 간격 스케일(4px 단위)을 기반으로, 프로젝트에 맞는 커스텀 값을 추가합니다.

theme: {
  extend: {
    spacing: {
      '18': '4.5rem',
      '88': '22rem',
      'content': '65ch', // 본문 최대 너비
    },
    fontSize: {
      'display': ['3.5rem', { lineHeight: '1.1', letterSpacing: '-0.02em' }],
      'heading': ['2rem', { lineHeight: '1.25', letterSpacing: '-0.01em' }],
      'body': ['1rem', { lineHeight: '1.75' }],
      'caption': ['0.875rem', { lineHeight: '1.5' }],
    },
  },
}

타이포그래피 토큰에 lineHeightletterSpacing을 함께 정의하면 매번 여러 유틸리티를 조합할 필요가 없어집니다.

Tailwind 설정 커스터마이징

Tailwind의 설정 파일은 디자인 시스템의 단일 진실 공급원(single source of truth)입니다. theme.extend 대신 theme을 직접 덮어쓰면 기본값을 완전히 교체할 수 있지만, 대부분의 경우 extend를 사용하여 기본값 위에 추가하는 것이 안전합니다.

프리셋(preset) 기능을 활용하면 여러 프로젝트에서 디자인 토큰을 공유할 수 있습니다.

// design-system-preset.js
module.exports = {
  theme: {
    extend: {
      colors: { /* 공통 색상 */ },
      fontFamily: { /* 공통 폰트 */ },
    },
  },
  plugins: [ /* 공통 플러그인 */ ],
};

// tailwind.config.js
module.exports = {
  presets: [require('./design-system-preset')],
  // 프로젝트별 추가 설정
};

컴포넌트 패턴

유틸리티 클래스만으로는 반복이 많아질 수 있습니다. 컴포넌트 단위로 패턴을 정리하면 코드의 가독성과 재사용성이 높아집니다.

버튼 컴포넌트 예시

import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';

const buttonVariants = cva(
  'inline-flex items-center justify-center rounded-lg font-medium transition-colors focus-visible:outline-none focus-visible:ring-2',
  {
    variants: {
      variant: {
        primary: 'bg-brand-500 text-white hover:bg-brand-600',
        secondary: 'bg-surface-secondary text-content hover:bg-surface-tertiary',
        ghost: 'text-content-secondary hover:bg-surface-secondary',
      },
      size: {
        sm: 'h-8 px-3 text-caption',
        md: 'h-10 px-4 text-body',
        lg: 'h-12 px-6 text-body',
      },
    },
    defaultVariants: {
      variant: 'primary',
      size: 'md',
    },
  }
);

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>,
  VariantProps<typeof buttonVariants> {}

export function Button({ className, variant, size, ...props }: ButtonProps) {
  return <button className={cn(buttonVariants({ variant, size }), className)} {...props} />;
}

class-variance-authority(CVA)를 사용하면 variant 기반의 스타일을 타입 안전하게 관리할 수 있습니다. 이 패턴은 shadcn/ui에서도 채택한 검증된 방식입니다.

반응형 디자인

Tailwind의 반응형 프리픽스는 모바일 퍼스트 원칙을 따릅니다. 기본 스타일이 모바일에 적용되고, sm:, md:, lg: 등의 프리픽스로 더 넓은 화면의 스타일을 추가합니다.

<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
  {items.map(item => <Card key={item.id} {...item} />)}
</div>

디자인 시스템에서 중요한 것은 브레이크포인트별 레이아웃 패턴을 사전에 정의하는 것입니다. 콘텐츠 영역의 최대 너비, 그리드 컬럼 수, 패딩 값 등을 문서화해두면 일관된 반응형 디자인을 유지할 수 있습니다.

다크 모드

Tailwind의 dark: 프리픽스와 시맨틱 색상 토큰을 조합하면 다크 모드를 체계적으로 구현할 수 있습니다.

/* CSS 변수 기반 접근 */
@layer base {
  :root {
    --color-surface: 255 255 255;
    --color-content: 33 37 41;
  }
  .dark {
    --color-surface: 26 27 30;
    --color-content: 222 226 230;
  }
}

CSS 변수를 활용하면 JavaScript 없이도 테마 전환이 가능하고, Tailwind 설정에서 rgb(var(--color-surface) / <alpha>) 형태로 투명도 조절까지 할 수 있습니다.

Tailwind CSS v4의 변화

Tailwind CSS v4는 설정 방식에 큰 변화를 가져왔습니다. JavaScript 설정 파일 대신 CSS 파일에서 직접 테마를 정의하는 CSS 우선 설정 방식을 채택했습니다.

@import "tailwindcss";

@theme {
  --color-brand-500: #4c6ef5;
  --color-brand-600: #3b5bdb;
  --font-display: "Pretendard", sans-serif;
  --breakpoint-sm: 640px;
}

Oxide 엔진으로 빌드 속도가 크게 향상되었고, @theme 디렉티브로 디자인 토큰을 CSS 네이티브하게 정의할 수 있게 되었습니다. 기존 JavaScript 설정에서 마이그레이션하는 것도 비교적 간단합니다.

마무리

디자인 시스템은 거창하게 시작할 필요가 없습니다. 색상과 타이포그래피 토큰을 정의하고, 자주 사용하는 컴포넌트 패턴 몇 가지를 만드는 것부터 시작하세요. Tailwind CSS는 이런 점진적 접근을 자연스럽게 지원하며, 프로젝트가 성장함에 따라 시스템도 함께 확장할 수 있습니다.

Tailwind CSS로 디자인 시스템 구축하기