Design tokens
디자인 토큰은 색, 글자 스타일, 간격, 모션 같은 디자인 결정을 이름과 값의 쌍으로 저장한 하나의 기준이에요.
brand.bold → 호버 brand.bold.hovered → 눌림 brand.bold.pressed디자인 토큰이란
디자인 토큰은 작고 재사용 가능한 디자인 결정 하나에 이름을 붙인 거예요. 예를 들어 성공 아이콘을 칠할 때 초록색 hex 값을 고르는 대신 color.icon.success 를 써요. 토큰 하나가 "무엇에 쓰는 값인지"를 담고 있어서, 디자이너와 개발자가 같은 이름으로 이야기할 수 있어요.
토큰을 쓰면 이런 점이 좋아요.
- 테마를 한 번에 바꿀 수 있어요 — 라이트·다크 모드처럼 값이 달라져도 코드는 그대로예요.
- 결정과 전달이 빨라져요 — 매번 색이나 간격을 고민하지 않고, 이름만 보고 골라요.
- 한곳에서 고치면 전체가 바뀌어요 — 하드코딩한 값을 찾아 바꿀 필요가 없어요.
- 화면이 일관돼요 — 모든 컴포넌트가 같은 기준값을 공유해요.
테마
테마는 같은 토큰 집합에 서로 다른 값을 넣은 묶음이에요. Steel 은 라이트와 다크 두 가지 색 테마를 제공해요. 토큰이 의미를 담고 있기 때문에, 같은 color.text.subtle 이 라이트에서는 진한 회색, 다크에서는 밝은 회색으로 알아서 바뀌어요.
이름 구조
토큰 이름은 최대 세 부분으로 이뤄져요.
| 부분 | 뜻 | 예 |
|---|---|---|
| Foundation | 토큰의 종류 | color, elevation, space, font, radius, motion |
| Property | 적용할 UI 속성 | text, background, border, icon, surface, shadow |
| Modifier (선택) | 역할, 강조 단계, 상호작용 상태 같은 세부 사항 | brand, bold, hovered, subtle |
color.background.brand.bold.hovered 를 나누면 이렇게 돼요.
color— 색 토큰이에요.background— 배경에 써요.brand— 브랜드 역할이에요.bold— 강조가 큰 단계예요.hovered— 마우스를 올린 상태예요.
Modifier 가 없는 토큰도 있어요. color.text 는 기본 본문 색이고, elevation.surface 는 기본 표면이에요.
토큰 종류
| 종류 | 토큰 수 | 무엇을 정하나요 |
|---|---|---|
Color color.* | 581 | 텍스트·링크·아이콘·배경·경계선·덮개·차트·스켈레톤·팔레트 |
Elevation elevation.* | 18 | 표면(surface)의 높이와 그림자(shadow) |
Space space.* | 38 | 8px 기반 간격 스케일과 gap·inset 시맨틱 간격 |
Radius radius.* | 8 | 모서리 둥글기 |
Border border.* | 3 | 경계선 두께 |
Typography font.* | 23 | 글자 스타일(크기·행간·굵기·서체 묶음), 굵기, 서체 |
Opacity opacity.* | 2 | 비활성·로딩 상태 투명도 |
Motion motion.* | 98 | 컴포넌트별 지속 시간과 가속 곡선 |
코드에서 쓰기
토큰은 세 가지 형태로 쓸 수 있어요. 이름의 점(.)을 하이픈(-)으로 바꾸고 --ds- 를 붙이면 CSS 변수가 되고, Tailwind 유틸은 그 이름 앞에 속성 접두어와 ds- 를 붙여요.
| 형태 | 규칙 | 예 |
|---|---|---|
| 토큰 이름 | foundation.property.modifier | color.background.brand.bold |
| CSS 변수 | --ds- + property 부터 하이픈 연결 | var(--ds-background-brand-bold) |
| Tailwind 색 | bg-ds-*, text-ds-*, border-ds-*, outline-ds-* | bg-ds-background-brand-bold |
| Tailwind 표면·그림자 | bg-ds-surface-*, shadow-ds-* | bg-ds-surface-raised shadow-ds-raised |
| Tailwind 간격 | p-ds-*, gap-ds-*, m-ds-* | p-ds-200, gap-ds-gap-medium |
| Tailwind 모서리 | rounded-ds-* | rounded-ds-medium |
| Tailwind 글자 | ds-font-* (단축 속성), font-ds-* (굵기) | ds-font-heading-medium, font-ds-medium |
| Tailwind 기타 | 임의값 문법으로 변수 참조 | opacity-(--ds-opacity-disabled), duration-(--ds-motion-popup-enter-top-duration) |
<button className="h-8 rounded-ds-medium bg-ds-background-brand-bold px-ds-150 ds-font-body font-ds-medium text-ds-text-inverse hover:bg-ds-background-brand-bold-hovered active:bg-ds-background-brand-bold-pressed">
이슈 만들기
</button>아래 표는 자주 쓰는 토큰의 매핑이에요. 값을 누르면 복사돼요.
| 토큰 | CSS 변수 | Tailwind | Light | Dark |
|---|---|---|---|---|
본문, 문장형 제목, 버튼 같은 기본 텍스트 | #292A2E | #CECFD2 | ||
내비게이션, 입력 필드 레이블처럼 한 단계 낮춘 보조 텍스트 | #505258 | #A9ABAF | ||
기본·호버 상태 링크. 호버 시 밑줄을 더해요 | #1868DB | #669DF1 | ||
color.text.subtle 과 짝을 이루는 아이콘 | #505258 | #A9ABAF | ||
평평한 카드, 패널 구분선처럼 UI 를 묶거나 나누는 기본 경계선 | #0B120E24 | #E3E4F21F | ||
키보드 포커스 링. 선택·호버 표시에 쓰지 않아요 | #4688EC | #8FB8F6 | ||
주요 버튼처럼 브랜드를 강하게 강조하는 배경 | #1868DB | #669DF1 | ||
color.background.brand.bold 의 호버 상태 | #1558BC | #8FB8F6 | ||
평소엔 배경이 없어 보이는 요소(subtle 버튼, 메뉴 항목) | #00000000 | #00000000 | ||
칸반 카드처럼 움직일 수 있는 카드 배경. shadow.raised 와 함께 | #FFFFFF | #242528 | ||
모달·드롭다운·플로팅 요소의 그림자. surface.overlay 와 함께 | 0px 8px 12px 0px #1e1f2126, 0px 0px 1px 0px #1e1f214f | 0px 0px 0px 1px #bdbdbd1f, 0px 8px 12px 0px #0104042a, 0px 0px 1px 1px #0104043b | ||
작고 촘촘한 UI | 8px | 테마 무관 | ||
관련 요소 사이의 중간 간격 | 8px | 테마 무관 | ||
중간 안쪽 여백 | 16px | 테마 무관 | ||
버튼, 입력, 텍스트 영역, 셀렉트, 내비게이션 항목 | 6px | 테마 무관 | ||
모든 기본 경계선과 구분선의 두께 | 1px | 테마 무관 | ||
모달 다이얼로그처럼 큰 컴포넌트의 제목 | normal 500 20px/24px | 테마 무관 | ||
컴포넌트와 짧은 설명의 기본 본문 | normal 400 14px/20px | 테마 무관 | ||
버튼처럼 아이콘 옆에 놓이는 텍스트 | 500 | 테마 무관 | ||
비활성 이미지(아바타 등)에 적용 | 0.4 | 테마 무관 | ||
150ms | 테마 무관 | |||
cubic-bezier(0.4, 1, 0.6, 1) | 테마 무관 |
다크 모드
다크 모드는 <html> 에 .dark 클래스가 붙으면 켜져요. 이때 --ds-* 변수의 값이 다크 테마 값으로 바뀌기 때문에, 컴포넌트 코드에 dark: 변형을 따로 쓸 필요가 없어요.
시맨틱 토큰은 테마마다 다른 팔레트 색을 참조해요.
| 시맨틱 토큰 | Light 참조 | Dark 참조 |
|---|---|---|
| palette.neutral-1000#292A2E | palette.dark-neutral-1000#CECFD2 | |
| palette.neutral-800#505258 | palette.dark-neutral-800#A9ABAF | |
| palette.blue-700#1868DB | palette.blue-400#669DF1 | |
| palette.neutral-0#FFFFFF | palette.dark-neutral-100#1F1F21 | |
| palette.neutral-0#FFFFFF | palette.dark-neutral-200#242528 | |
| palette.neutral-300a#0B120E24 | palette.dark-neutral-300a#E3E4F21F |
dark: 변형을 쓰지 마세요
dark:bg-... 로 다크 값을 직접 지정하면 토큰이 바뀔 때 함께 바뀌지 않아요. 다크에서 다른 색이 필요하다면 그 의미에 맞는 다른 토큰이 있는지 먼저 찾아보세요.
토큰 고르는 법
- 의미로 고르세요. 색이 비슷해 보인다는 이유로 토큰을 고르면 다른 테마에서 어긋나요. 예를 들어 선택된 항목에
color.background.brand.subtlest를 쓰지 말고color.background.selected를 써요. - 짝을 맞추세요.
elevation.surface.raised에는elevation.shadow.raised,color.text.subtle옆 아이콘에는color.icon.subtle처럼 함께 쓰도록 만든 짝이 있어요. - 팔레트 토큰은 마지막 수단이에요.
color.palette.*는 테마가 바뀌어도 값이 그대로라서, 시맨틱 토큰으로 표현할 수 없는 경우에만 써요. - 임의 값은 피하세요. hex 나 px 를 직접 쓰기 전에 Color, Spacing, Typography 에서 맞는 토큰을 찾아보세요.