디자인 시스템 사용해보기(2): Vapor (by goorm)

 

이번 해커톤은 Vapor 디자인 시스템을 사용하여 진행하게 되었습니다!
 
 🔗Vapor UI
이에 앞서, 꼭 알아야 할 요소들을 Docs 기반으로 가볍게 정리해봤습니다.
이 정도만 알아도 어떻게 사용하면 될지 감이 올 것 같습니다.

 


꼭 알아야 하는 10가지

1. 설치 & 전역 스타일

  • 패키지: @vapor-ui/core + 아이콘이면 @vapor-ui/icons까지 설치.
  • 전역에 Vapor CSS를 반드시 import. (Next/App Router는 app/layout.tsx, Vite는 src/main.tsx)
// 전역(예: app/layout.tsx 또는 main.tsx)
import '@vapor-ui/core/styles.css';

 

2. Tailwind CSS와의 통합 (v4)

  • Vapor는 Tailwind v4와 잘 붙도록 문서가 준비돼 있음.
  • global.css에서 레이어 순서import를 아래처럼 맞추면 끝.
  • 핵심: Tailwind 유틸리티(tw-utilities)가 항상 우선순위 최상위 → 필요시 Tailwind 클래스로 Vapor 기본 스타일을 덮어쓰기 쉬움. 또한 Tailwind의 preflight는 기본적으로 비권장(충돌 방지). 꼭 써야 하면 레이어 순서 조정.
/* global.css */
@layer tw-theme, theme, reset, components, utilities, tw-utilities;

@import 'tailwindcss/theme.css' layer(tw-theme);
@import 'tailwindcss/utilities.css' layer(tw-utilities);

@import '@vapor-ui/core/styles.css';
@import '@vapor-ui/core/tailwind.css';

 

3. Vapor 전용 유틸리티 클래스(토큰 기반)

  • @vapor-ui/core/tailwind.css를 넣으면 v- 접두사 유틸리티 사용 가능.
  • 예시: bg-v-primary, text-v-danger, p-v-200, rounded-v-300 등. 토큰 네임스페이스(color, spacing, radius, font-weight 등)와 Tailwind 기본 유틸리티를 조합해서 사용. (Vapor UI)

 

4. 디자인 토큰(색/크기/타이포)

  • Color: gray 컬러, 상태 색(primary/secondary/success/warning/danger 등)과 시맨틱 컬러 제공.
  • Size: 간격/크기 스케일을 일관되게.
  • Typography: 폰트 패밀리, 사이즈, 굵기, line-height 등 시스템화.
  • ⭐토큰 페이지를 참고해 임의 값 대신 토큰 우선 사용. 유지보수성↑.

 

5. 레이아웃 프리미티브 먼저 쓰기

  • Box / Flex / Grid / HStack / VStack이 기본 빌딩 블록.
  • 예) 레이아웃은 Box, 1차 배치는 Flex(또는 H/VStack), 격자는 Grid로—가능한 한 컴포넌트 속성 + 토큰/유틸리티로 해결. 
import { Box, HStack, Grid } from '@vapor-ui/core';

export default function Section() {
  return (
    <Box padding="$400" backgroundColor="gray-100" borderRadius="$300">
      <HStack gap="4">
        <div className="p-4 rounded bg-v-primary text-white">A</div>
        <div className="p-4 rounded bg-v-secondary text-white">B</div>
      </HStack>

      <Grid columns="1fr 2fr" gap="$300" className="mt-4">
        <div className="bg-v-normal-lighter p-v-200 rounded-v-200">Left</div>
        <div className="bg-v-normal p-v-200 rounded-v-200">Right</div>
      </Grid>
    </Box>
  );
}

 

6. 컴포넌트 패턴(Compound + render prop) — asChild 아님!

Vapor의 다수 컴포넌트는 .Root / .Trigger / .Content ... 식의 컴파운드 패턴을 사용.

  • 버튼을 트리거로 감쌀 때 asChild가 아니라 render prop을 씀.
import { Button, Dialog } from '@vapor-ui/core';

export default function Demo() {
  return (
    <Dialog.Root>
      <Dialog.Trigger render={<Button>열기</Button>} />
      <Dialog.Content>
        <Dialog.Header>
          <Dialog.Title>알림</Dialog.Title>
          <Dialog.Close aria-label="Close" />
        </Dialog.Header>
        <Dialog.Body>
          <Dialog.Description>본문…</Dialog.Description>
        </Dialog.Body>
        <Dialog.Footer>
          <Dialog.Close render={<Button variant="ghost">취소</Button>} />
          <Button color="primary">확인</Button>
        </Dialog.Footer>
      </Dialog.Content>
    </Dialog.Root>
  );
}

 

7. 상태/사이즈/변형 Props의 공통성

  • 예: Button은 color(primary|secondary|success|warning|danger|contrast), variant(예: outline, ghost), size 등을 공통 인터페이스처럼 제공. 팀 내에서 허용 색상/사이즈 테이블을 공유해 일관성 유지.

 

8. 아이콘 사용법

  • @vapor-ui/icons에서 바로 import. (Docs의 Icons 페이지에서 클릭하면 import 예시 복사 가능)
  • IconButton 같이 텍스트 없는 액션엔 접근성 고려(aria-label 필수).
import { IconButton } from '@vapor-ui/core';
import { HeartIcon } from '@vapor-ui/icons';

<IconButton aria-label="좋아요" render={<HeartIcon />} />;

 

9. 접근성(A11y) 기본 장착

  • Vapor 컴포넌트는 ARIA/키보드 내비게이션을 기본 지원. 하지만 문맥에 맞는 aria-label/Title/Description을 넣는 건 개발자 몫. 다이얼로그엔 Title/Description을 꼭 포함. (Vapor UI)

 

10. 변경 이력 확인하며 버전 고정

  • 컴포넌트 prop/토큰 네이밍이 가끔 바뀌니 Releases를 주기적으로 체크하고 패치 시 팀에 공지. CI에서 @vapor-ui/* 버전 범위를 명시해 예기치 않은 브레이킹 방지. (Vapor UI)

 

빠른 스타터 체크리스트

  • @vapor-ui/core(+ @vapor-ui/icons) 설치 & 전역 styles.css import 완료
  • Tailwind v4면 global.css에 레이어/임포트 정확히 배치, @vapor-ui/core/tailwind.css 포함
  • 새 화면은 Box/Flex/Grid/HStack/VStack 조합으로 시작
  • 색/간격/모서리/폰트는 토큰 기반 유틸리티(v- 접두) 우선 사용
  • 모달·툴팁·메뉴 등은 Compound + render prop 패턴으로 구성 (asChild X)
  • 아이콘은 @vapor-ui/icons에서 import, 텍스트 없는 컨트롤엔 aria-label 필수

 

자주 쓰는 컴포넌트 미니 레시피

  • 버튼 색/변형 예시
<Button color="primary">확인</Button>
<Button color="secondary" variant="outline">취소</Button>
<Button color="danger" size="sm">삭제</Button>
  • 툴팁(트리거는 render 사용)
import { Button, Tooltip } from '@vapor-ui/core';

<Tooltip.Root>
  <Tooltip.Trigger render={<Button>툴팁 보기</Button>} />
  <Tooltip.Content>유용한 정보</Tooltip.Content>
</Tooltip.Root>;
  • 메뉴(드롭다운)
import { Button, Menu } from '@vapor-ui/core';

<Menu.Root>
  <Menu.Trigger render={<Button>메뉴 열기</Button>} />
  <Menu.Content>
    <Menu.Item>새 파일</Menu.Item>
    <Menu.Item>복사</Menu.Item>
    <Menu.Separator />
    <Menu.Item color="danger">삭제</Menu.Item>
  </Menu.Content>
</Menu.Root>;

 
 

팀의 코딩 규칙 정해보기

  • 토큰 우선: 색/간격/반경/폰트는 임의 값 대신 Vapor 토큰(bg-v-*, p-v-*, rounded-v-*) 사용.
  • 컴파운드 + render: 서드파티 패턴(asChild 등) 혼용 금지. Vapor 문서 패턴만.
  • 레이아웃 계층: Box(섹션) → Flex/HStack/VStack(정렬) → Grid(격자) 순으로 설계.
  • A11y: 텍스트 없는 컨트롤에 aria-label 필수, Dialog에 Title/Description 포함.
  • 릴리즈 트래킹: 릴리즈 노트 확인 후 버전 범위 적절히 업데이트.

 

'웹 개발 일기' 카테고리의 다른 글

디자인 시스템 사용해보기(1): Vapor (by goorm)  (0) 2025.09.20