# Badge 상태나 속성을 짧은 라벨로 강조해, 목록에서 훑어보는 것만으로 구분되게 만드는 표식입니다. > 원본: `03_ASSET_GUIDE/catalog/badge.js` · CSS: `03_ASSET_GUIDE/styles/elements/badge.css` > kind `element` · category `feedback` · status `stable` · specSource `measured` --- ## 1. 구성 Badge 는 Label 을 감싸는 **Container** 로 구성되고, 의미를 보강할 필요가 있을 때만 Icon 을 앞에 붙입니다. ``` ┌──────────────────┐ │ [✓] 인증 완료 │ └──────────────────┘ ① ② ③ ``` | # | 요소 | 필수 | 클래스 | 설명 | |---|---|---|---|---| | ① | Container | 필수 | `atom-badge` | 배경·모서리·높이를 담당하는 `` 입니다. | | ② | Icon | 선택 | `atom-badge__icon` | 라벨 앞에 놓이는 아이콘. 앞쪽 하나로 제한합니다. | | ③ | Label | 필수 | — (텍스트 노드) | 상태를 말하는 짧은 명사입니다. | > [!NOTE] > Badge 는 **누를 수 없는 표식**입니다. 사용자가 눌러 상태를 바꿀 수 있어야 한다면 > Chip 을 사용하세요. 카탈로그의 `chip` · `action-chip` · `control-chip` 이 그 역할입니다. --- ## 2. 종류 / 크기 ### Variant Solid 는 배경을 채워 가장 강하게 눈에 띄고, Weak 는 같은 의미를 옅은 배경으로 전달합니다. Outline 은 배경 없이 테두리만 씁니다. | Variant | 의미 | 예시 라벨 | |---|---|---| | `neutralSolid` | 중립 · 분류 | 신규, 공지 | | `brandSolid` | 브랜드 강조 | Pro, 베타 | | `criticalSolid` | 즉시 확인해야 하는 문제 | 오류, 사용 중지 | | `neutralWeak` | 부가 정보 | 초안, 보관됨 | | `brandWeak` | 브랜드 강조 (약) | 업그레이드 | | `positiveWeak` | 완료 · 성공 | 활성, 배포 완료 | | `informativeWeak` | 안내 | 동기화중 | | `warningWeak` | 주의 | 검토 필요, 만료예정 | | `neutralOutline` | 배경과 대비가 필요할 때 | v2.1, Admin | Solid 는 세 가지(neutral · brand · critical)뿐입니다. positive · informative · warning 에는 Solid 가 없습니다. 성공이나 안내는 즉시 시선을 끌어야 하는 정보가 아니기 때문입니다. ### Size `small` 은 리스트 행처럼 세로 공간이 빡빡한 곳에, `medium` 은 그 밖의 모든 곳에 사용합니다. | Size | 높이 | 좌우 여백 | 폰트 | 아이콘 | |---|---|---|---|---| | `small` | 19px | 6px | 10px | 10px | | `medium` | 23px | 8px | 11px | 12px | ### Shape 기본은 `square`(4px) 입니다. 같은 화면에 Chip 이 함께 있어 서로 혼동될 때만 `pill` 을 골라 형태로 구분합니다. `pill` 은 모서리를 `--atom-radius-full` 로 바꾸고 좌우 여백을 8px → 9px 로 1px 늘립니다. 모서리가 둥글면 같은 여백에서도 좁아 보이기 때문입니다. ### Icon 라벨만으로 의미가 전달되지 않을 때만 아이콘을 붙입니다. 아이콘은 앞쪽 하나로 제한합니다. ### 클래스 계약 `styles/elements/badge.css` 헤더와 원본 `registry.json` `css.blocks` 기준입니다. 클래스가 없는 값(—)은 기본 스타일 그대로입니다. | Prop | 값 | 클래스 | |---|---|---| | `variant` | `neutralSolid` · `brandSolid` · `criticalSolid` · `neutralWeak` · `brandWeak` · `positiveWeak` · `informativeWeak` · `warningWeak` · `neutralOutline` | `--variant_neutral-solid` · `--variant_brand-solid` · `--variant_critical-solid` · `--variant_neutral-weak` · `--variant_brand-weak` · `--variant_positive-weak` · `--variant_informative-weak` · `--variant_warning-weak` · `--variant_neutral-outline` | | `size` | `small` · `medium` | `--size_small` · — | | `shape` | `square` · `pill` | — · `--shape_pill` | | `icon` | | `__icon` | 상태 선택자: 없음 (`css.states` 가 비어 있습니다). --- ## 3. 상태 Badge 는 누를 수 없는 표식이라 상태(hover · pressed · disabled 등)가 없습니다. 원본 CSS 에도 상태 선택자가 없습니다. --- ## 4. Props | Prop | Type | Default | 필수 | 설명 | |---|---|---|---|---| | `variant` | `"neutralSolid" \| "brandSolid" \| "criticalSolid" \| "neutralWeak" \| "brandWeak" \| "positiveWeak" \| "informativeWeak" \| "warningWeak" \| "neutralOutline"` | `"neutralSolid"` | | 배지의 의미와 색을 결정합니다. | | `size` | `"small" \| "medium"` | `"medium"` | | 높이와 폰트 크기를 결정합니다. | | `shape` | `"square" \| "pill"` | `"square"` | | 모서리 반경을 결정합니다. | | `icon` | `ReactNode` | | | 라벨 앞에 놓일 아이콘입니다. | | `children` | `ReactNode` | | ● | 라벨 텍스트입니다. | ### Parts (compound) | Part | 요소 | 설명 | |---|---|---| | `Badge` | `` | Container. 위 Props 를 받습니다. 라벨은 텍스트 노드로 그대로 둡니다. | | `Badge.Icon` | 자식 요소(svg)에 `atom-badge__icon` 을 합침 | 라벨 앞 아이콘. `icon` prop 과 같은 결과입니다. `aria-hidden` | --- ## 5. Component tokens | 대상 | 속성 | Token | Value | |---|---|---|---| | Container | gap | `{space.x1}` | 4px | | Container | radius | `{radius.r1}` | 4px | | Container (`pill`) | radius | `{radius.full}` | 9999px | | `neutralSolid` | background · color | `{color.bg.neutral-solid}` · `{color.fg.on-solid}` | | | `brandSolid` | background | `{color.primary.600}` | `#383fae` | | `criticalSolid` | background | `{color.bg.critical-solid}` | | | `neutralWeak` | background · color | `{color.bg.neutral-weak}` · `{color.fg.neutral-muted}` | | | `brandWeak` | background · color | `{color.primary.50}` · `{color.primary.700}` | | | `positiveWeak` | background · color | `{color.green.50}` · `{color.green.700}` | | | `informativeWeak` | background · color | `{color.blue.50}` · `{color.blue.600}` | | | `warningWeak` | background · color | `{color.bg.warning-weak}` · `{color.fg.warning}` | | | `neutralOutline` | border | `{color.border.default}` 1px inset | | > [!NOTE] > `brandWeak` · `positiveWeak` · `informativeWeak` 세 개는 역할 토큰이 아니라 **팔레트를 > 직접** 참조합니다. `--atom-bg-brand-weak` · `--atom-bg-positive-weak` 같은 짝이 없기 > 때문입니다. `warningWeak` 만 역할 토큰을 씁니다. > Color 의 원칙에 어긋나므로 역할 토큰을 추가해 정리할 여지가 있습니다. 높이(19 · 23px), 좌우 여백(6 · 8 · 9px), 폰트(10 · 11px), 아이콘(10 · 12px)은 토큰이 아닙니다. ```json { "badge": { "gap": { "$type": "dimension", "$value": "{space.x1}" }, "radius": { "$type": "dimension", "default": { "$value": "{radius.r1}" }, "pill": { "$value": "{radius.full}" } }, "neutral-solid": { "$type": "color", "bg": { "$value": "{color.bg.neutral-solid}" }, "fg": { "$value": "{color.fg.on-solid}" } }, "brand-solid": { "$type": "color", "bg": { "$value": "{color.primary.600}" }, "fg": { "$value": "#ffffff" } }, "critical-solid": { "$type": "color", "bg": { "$value": "{color.bg.critical-solid}" }, "fg": { "$value": "#ffffff" } }, "neutral-weak": { "$type": "color", "bg": { "$value": "{color.bg.neutral-weak}" }, "fg": { "$value": "{color.fg.neutral-muted}" } }, "brand-weak": { "$type": "color", "bg": { "$value": "{color.primary.50}" }, "fg": { "$value": "{color.primary.700}" } }, "positive-weak": { "$type": "color", "bg": { "$value": "{color.green.50}" }, "fg": { "$value": "{color.green.700}" } }, "informative-weak": { "$type": "color", "bg": { "$value": "{color.blue.50}" }, "fg": { "$value": "{color.blue.600}" } }, "warning-weak": { "$type": "color", "bg": { "$value": "{color.bg.warning-weak}" }, "fg": { "$value": "{color.fg.warning}" } }, "neutral-outline": { "$type": "color", "border": { "$value": "{color.border.default}" }, "fg": { "$value": "{color.fg.neutral}" } } } } ``` --- ## 6. 접근성 - **요소** — `` 입니다. 누를 수 없는 표식이므로 `role` 을 붙이지 않습니다. 포커스도 받지 않습니다. - **읽히는 순서** — Badge 는 대상 바로 옆에 놓이지만 DOM 상으로는 별개 요소입니다. 스크린리더는 "제목 — 신규" 처럼 이어 읽습니다. 대상과 배지 사이에 다른 요소를 끼우지 않아야 이 순서가 유지됩니다. - **아이콘** — `aria-hidden="true"` 를 붙입니다. 라벨이 의미를 전하므로 아이콘까지 읽으면 중복입니다. - **대비** — `criticalSolid` 의 흰 라벨은 라이트 모드에서 **3.91:1** 입니다. 배지 폰트는 10–11px 라 "큰 텍스트" 예외를 받지 못하므로, 본문 기준 4.5:1 에 미달합니다. Color 의 Accessibility 항목에 정리되어 있습니다. - **최소 크기** — `small` 의 10px 는 Typography 가 권하는 최소 12px 보다 작습니다. 배지는 숫자나 2~5자 명사라 문장이 아니므로 예외로 두지만, 문장을 이 크기로 넣지 않습니다. --- ## 7. 사용 가이드 ### 제목 옆에 붙이기 Badge 는 대상 바로 옆에 붙습니다. 무엇에 대한 상태인지 모호해지는 위치에는 두지 않습니다. ### 한 대상에 하나만 Badge 가 여러 개 붙으면 어느 것도 강조되지 않습니다. 가장 중요한 상태 하나만 남기세요. - ✅ **Do** 지금 판단에 필요한 상태 하나만 노출합니다. - ❌ **Don't** 상태를 모두 나열하지 않습니다. ### 라벨은 2~5자 - ✅ **Do** 상태를 명사로 짧게 적습니다. - ❌ **Don't** 문장을 넣지 않습니다. 설명이 필요하면 본문에 적으세요. Container 에 `white-space: nowrap` 이 걸려 있어 라벨은 줄바꿈되지 않습니다. 긴 라벨은 줄이 늘어나는 대신 레이아웃을 밀어냅니다. ### Badge · Chip · Tag 구분하기 셋 다 작고 둥근 라벨입니다. **누를 수 있는지**로 구분합니다. | 상황 | 쓸 컴포넌트 | |---|---| | 상태를 보여주기만 한다 | **Badge** | | 눌러서 목록을 좁히거나 속성을 토글한다 | Chip (`chip` · `control-chip`) | | 눌러서 액션을 실행한다 | Chip (`action-chip`) 또는 `xsmall` [Button](./button.md) | | 여러 개를 지웠다 붙였다 한다 | Tag Group (`tag-group`) | | 알림 개수를 숫자로 표시한다 | Notification Badge (`notification-badge`) | ### 색만으로 의미를 전하지 않습니다 `positiveWeak` 와 `criticalWeak` 를 색으로만 구분하면 색각 이상 사용자는 구분할 수 없습니다. 라벨 텍스트에 의미를 담습니다. - ✅ **Do** "활성" · "오류" 처럼 라벨 자체가 상태를 말하게 합니다. - ❌ **Don't** 색이 다른 빈 배지로 상태를 구분하지 않습니다. --- ## 8. 예시 ```tsx }>본인 인증 신규 ``` ```html 본인 인증 ```