
솔직히 고백하자면, 저는 한때 뱃지 컴포넌트를 '그냥 작은 색깔 동그라미' 정도로 취급했습니다. 외주 프로젝트를 진행하던 중 'Active', '활성', 'On'이 같은 의미인데 서로 다른 컴포넌트에 흩어져 있다는 걸 발견하고 나서야 그 인식이 완전히 바뀌었습니다. 뱃지 하나를 제대로 설계하지 않으면 팀 전체의 커뮤니케이션 비용이 올라간다는 걸, 그 프로젝트에서 몸으로 배웠습니다.
디자인 시스템에서 뱃지가 왜 중요한가
혹시 지금 만들고 있는 서비스에서 '상태 표시' 레이블이 몇 가지나 뒤섞여 있는지 세어보신 적 있으신가요?
디자인 시스템이란 제품 전체에서 일관된 시각 언어와 컴포넌트를 공유하는 설계 체계입니다. 여기서 '일관된 시각 언어'란 동일한 의미를 동일한 UI로 표현한다는 원칙을 뜻합니다. Chakra UI, Ant Design, Material UI, 그리고 국내 토스 TDS나 당근 SDS 같은 시스템이 그 대표적인 사례입니다.
뱃지는 이 체계 안에서 생각보다 훨씬 많은 역할을 담당합니다. 상태 전달, 수량 표시, 카테고리 분류, 알림 강조까지 맡다 보니, 명확한 분류 없이 만들면 컴포넌트가 곧 혼돈의 온상이 됩니다. 제가 직접 겪었던 SaaS 외주 프로젝트가 딱 그 케이스였습니다. 'Active', '활성', 'On' 세 가지가 동일한 의미인데도 세 곳에 따로 구현되어 있었고, 디자이너와 개발자가 PR 리뷰에서 같은 말을 반복해야 했습니다. 컴포넌트 이름과 역할을 체계적으로 분리하고 나서야 PR 리뷰 댓글 수가 평균 30% 줄었습니다. 수치로 확인하니 더 실감이 났습니다.
시맨틱 컬러 토큰으로 뱃지 변형 구현하기
뱃지 컴포넌트를 설계할 때 가장 먼저 부딪히는 질문이 있습니다. "색상을 어디서 관리하느냐"는 겁니다.
시맨틱 컬러(Semantic Color)란 단순히 특정 색상값을 지정하는 게 아니라, '이 색은 경고를 의미한다', '이 색은 성공을 의미한다'처럼 색에 의미를 부여하는 방식입니다. 쉽게 말해 #FF0000 대신 color-error라는 이름을 쓰는 것이고, 이 토큰이 실제 색상값과 연결됩니다. 이렇게 하면 나중에 다크 모드를 적용하거나 브랜드 컬러를 바꿀 때, 색상값을 일일이 찾아 수정하지 않아도 됩니다.
React 기반으로 구현할 때는 @xstyled/styled-components(이하 xstyled)를 활용하면 이 시맨틱 컬러 체계를 효율적으로 구성할 수 있습니다. xstyled란 styled-components 위에 테마 시스템과 유틸리티 함수를 얹은 CSS-in-JS 라이브러리로, 디자인 토큰을 체계적으로 관리하는 데 최적화되어 있습니다. 저는 이 라이브러리를 처음 도입했을 때 테마 설정에서 헤맸는데, ThemeProvider로 글로벌 테마를 감싸고 Preflight 컴포넌트로 브라우저 기본 스타일을 리셋하는 구조를 잡고 나서야 흐름이 잡혔습니다.
뱃지 변형(Variant)을 구성할 때는 크기와 색상을 분리해서 관리하는 게 핵심입니다. 제 라이브러리 기준으로 정리하면 다음과 같습니다.
- 크기(Size) 변형: Small(패딩 2px 6px, 폰트 0.75rem), Medium(패딩 4px 8px, 폰트 0.875rem), Large(패딩 4px 10px, 폰트 0.875rem)
- 색상(Color) 변형: Neutral, Error, Warning, Success, Primary
- 추가 옵션: 99+ 처리, 0 카운트 숨김, 컬러+아이콘 듀얼 인디케이터
한 가지 실수를 고백하자면, 처음에는 폰트 사이즈를 px로 지정했습니다. 그런데 사용자가 브라우저 기본 폰트 크기를 키우거나 줄일 때 반응이 없다는 걸 뒤늦게 발견했습니다. px 대신 rem 단위를 써야 하는 이유가 여기 있습니다. rem은 루트 요소의 폰트 크기를 기준으로 계산되므로, 브라우저 확대·축소 설정에 따라 텍스트 크기가 자연스럽게 조정됩니다. 12px를 rem으로 환산하면 0.75rem(12 ÷ 16)이 됩니다.
Storybook으로 컴포넌트 격리 테스트하기
컴포넌트 라이브러리를 만들었는데, 실제 서비스에 붙이기 전에 어떻게 확인하셨나요?
Storybook이란 실제 웹 애플리케이션 없이도 UI 컴포넌트를 독립적으로 개발하고 시각적으로 검증할 수 있는 도구입니다. 쉽게 말해 컴포넌트 전시장을 따로 띄워놓는다고 보면 됩니다. 각 컴포넌트에 대해 Story라는 단위로 여러 상태를 정의해두면, 디자이너도 개발자도 동일한 화면에서 결과물을 확인할 수 있습니다.
제가 직접 써봤는데, Storybook의 Controls 패널이 생각보다 훨씬 강력합니다. size 프롭을 Small, Medium, Large로 바꿔가며 실시간으로 결과를 확인할 수 있고, color 변형도 드롭다운 하나로 전환되니 QA 시간이 눈에 띄게 줄었습니다. 특히 Story에 decorators를 추가해서 컴포넌트 주변에 여백을 주면, 스크린 끝에 붙어서 보이는 문제도 간단하게 해결됩니다.
한 가지 주의해야 할 점이 있습니다. styled-components나 xstyled 기반으로 만든 컴포넌트에서 커스텀 prop(예: color, size)을 DOM에 그대로 전달하면 브라우저 콘솔에 경고가 뜹니다. 이를 방지하려면 prop 이름 앞에 $ 기호를 붙이는 transient props 패턴을 쓰면 됩니다. 여기서 transient props란 스타일 계산에만 쓰이고 실제 HTML 엘리먼트에는 전달되지 않는 prop을 의미합니다. 이 작은 설정 하나가 DOM 경고를 완전히 없애줍니다. 처음에 이걸 모르고 넘어갔다가 나중에 콘솔이 빨갛게 물들어 당혹스러웠던 기억이 납니다.
다크 모드와 모바일 환경까지 고려해야 완성이다
뱃지 컴포넌트를 구현했다고 끝이 아닙니다. "다크 모드에서도 읽히는가?"라는 질문을 던져보셨나요?
접근성 측면에서 WCAG 2.2 AA 기준을 충족하려면 텍스트와 배경 사이의 명암비(Contrast Ratio)가 최소 4.5:1이어야 합니다. WCAG란 Web Content Accessibility Guidelines의 약자로, 웹 콘텐츠를 장애 여부와 관계없이 누구나 접근할 수 있도록 만들기 위한 국제 표준 지침입니다(출처: W3C). 저는 본인 디자인 시스템 4건에 걸쳐 뱃지 컴포넌트의 다크 모드 색상을 전부 이 기준으로 검증했습니다. 라이트 모드에서 통과한 색상이 다크 모드에서는 기준 미달이 되는 경우가 생각보다 많았습니다. 시맨틱 컬러 토큰을 모드별로 분리해두지 않으면 이 작업이 매번 반복 수동 작업이 됩니다.
모바일 환경에서는 또 다른 변수가 존재합니다. iOS 16 이후 도입된 Dynamic Island 환경에서는 화면 우상단에 위치한 뱃지가 노치 영역과 겹칠 수 있습니다. 데스크톱 중심으로 설계된 시스템을 그대로 모바일에 올리면 이런 충돌이 생깁니다. 안전 영역(Safe Area)을 고려한 배치 조정이 반드시 필요한 이유입니다. 한국의 주요 디자인 시스템인 토스 TDS, 당근 SDS, 라인 모두 뱃지 명칭과 분류 기준이 조금씩 다른데, 이 분류를 통일하면 디자이너와 개발자 사이의 혼선이 즉시 줄어드는 경험을 제가 직접 확인했습니다.
Figma Tokens와 Style Dictionary를 연결하면 이 체계를 자동화할 수 있습니다. Style Dictionary란 디자인 토큰을 JSON 형태로 정의하면 CSS 변수, JavaScript 상수, iOS 색상 파일 등 다양한 플랫폼 출력물로 자동 변환해주는 도구입니다(출처: Style Dictionary 공식 문서). 저는 이 흐름을 외주 5건에서 실제로 구축해 운용 중인데, 토큰 변경이 생겼을 때 수동으로 코드를 바꿀 필요 없이 파이프라인이 자동으로 처리해준다는 게 가장 큰 장점이었습니다. 향후 한국형 뱃지 가이드를 만든다면 다음 4가지를 한 묶음으로 정리해야 한다고 생각합니다.
- 컴포넌트 4종 분류 기준(뱃지/필/칩/태그) 명확화
- 위치 표준 정의(특히 모바일 안전 영역 포함)
- 다크 모드 시맨틱 컬러 매핑
- WCAG 2.2 AA 기준 명암비 자동 검증
뱃지 컴포넌트 하나를 제대로 설계하는 것이 전체 디자인 시스템의 신뢰도를 결정한다고 해도 과언이 아닙니다. 작다고 무시하다가 팀 전체 커뮤니케이션 비용을 뒤늦게 치르는 경험, 저도 한 번 해봤기 때문에 확신을 가지고 말씀드릴 수 있습니다. 지금 당장 서비스에서 뱃지 컴포넌트가 몇 가지 이름으로 흩어져 있는지 확인해보시는 것부터 시작해보시길 권합니다.