ComponentsP3 본문

Tag

칩/태그 — variant 5종 × size 2단. onRemove를 주면 히트 영역이 확장된 제거 버튼이 붙는 입력성 칩이 됩니다.

마지막 업데이트 2026-06-22

한눈에#

적용된 필터·선택 항목처럼 사용자가 다루는 값을 표시하는 칩입니다 — onRemove를 주면 제거 가능한 입력성 칩이 됩니다.

디자인 시스템React배포됨검토 중
  • 의미 5종 × 2 크기
  • onRemove 입력성 칩
  • 제거 히트 확장
  • 긴 라벨 말줄임

제거 버튼은 시각은 작아도 ::after로 히트 영역이 확장됩니다(버튼 박스 20px → 44px)

사용 시점#

사용자가 다루는 값(필터·선택 항목)을 라벨로 보여주면 Tag — 상호작용 칩이나 읽기 전용 표식은 다른 컴포넌트입니다.

권장 — 이렇게 쓰세요

지양 — 이러지 마세요

ReactTypeScript

쓴다적용된 필터·선택 항목처럼 사용자가 다루는 값(onRemove로 제거 가능한 입력성 칩)

대신 Chip클릭으로 토글·실행되는 인터랙션 칩(assist/filter/input/suggestion)

대신 Badge수량·상태처럼 사용자가 다루지 않는 읽기 전용 표식

플레이그라운드#

컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.

Tag를 직접 조작해 보세요

속성·테마·토큰을 바꾸고 React·Flutter 코드를 확인하는 풀스크린 빌더로 엽니다.

빌더 열기

플레이그라운드는 넓은 작업 영역이 필요해 웹·태블릿에서 편집할 수 있어요.

해부#

알약 위에 토큰 실측을 핀으로 얹습니다 — 값이 바뀌면 핀도 함께 움직입니다(드리프트 0).

md · variant primary — 실물 렌더 위에 토큰 실측을 핀으로 표기
React
padding-inline
12pxspace-3
padding-block
4pxspace-1
gap
4pxspace-1
radius
fullradius-full
font
14 / 500body-2
remove hit
44px (::after)

알약은 radius.full로 콘텐츠 높이에 맞춰 둥글어집니다 — 명시 높이 토큰 없이 패딩과 폰트가 높이를 결정합니다. 제거 버튼은 버튼 박스 20px(icon.size-md, 글리프 16px)이고 히트 영역은 ::after로 44px까지 확장됩니다.

변형#

5단 의미 색. 색은 이름이 아니라 실제 스와치와 측정된 대비로 확인하세요 — 상태색은 base 색의 8% color-mix 틴트 위에 *-text 잉크로 AA 4.5:1을 보장합니다.

neutral
neutral
bg
surface-muted
fg
text-muted
라이트 · AA 보장
primary
primary
bg
primary-subtle
fg
primary-text
라이트 · AA 보장
success
success
bg
success 8%
fg
success-text
라이트 · AA 보장
warning
warning
bg
warning 8%
fg
warning-text
라이트 · AA 보장
error
error
bg
error 8%
fg
error-text
라이트 · AA 보장

틴트는 8% 고정입니다 — 12%는 success-text와 4.39:1로 AA 미달(선례 실측). 대비 배지는 라이트 테마 기준이며, 다크 테마에서도 다섯 변형 모두 AA(4.5:1 이상)를 보장합니다.

크기#

size로 2단 — sm(caption 폰트)·md(body-2 폰트). 두 크기 모두 알약 형태와 제거 버튼 히트 영역을 공유하고, 인라인 패딩만 달라집니다.

sm · md — 공유 베이스라인에서 패딩·폰트차 비교
작은 태그보통 태그
sizepadding-inlinepadding-blockfontremove hitsm8px4px12px (caption)44pxmd12px4px14px (body-2)44px

상태#

onRemove를 제공하면 제거 버튼(CloseIcon)이 렌더됩니다. 함수 prop은 서버 MDX로 전달할 수 없어 코드로 보입니다:

'use client';

function FilterTags({ filters, onRemove }: FilterTagsProps) {
  return filters.map((filter) => (
    <Tag key={filter} variant="primary" onRemove={() => onRemove(filter)}>
      {filter}
    </Tag>
  ));
}
  • 제거 버튼은 기본 70% 투명도, hover 시 100% — 라벨보다 조용하게 유지됩니다
  • 긴 라벨은 말줄임(ellipsis) 처리됩니다 (max-width: 100%)

Props#

Prop타입기본값설명
variant'neutral' | 'primary' | 'success' | 'warning' | 'error'neutral의미 색 — *-text 잉크 + 8% 틴트(neutral은 surface-muted)
size'sm' | 'md'mdsm은 caption, md는 body-2 폰트
onRemove() => void제공 시 제거 버튼을 렌더하고 클릭 시 호출
removeLabelstring제거제거 버튼 aria-label (기본 '제거')
refRef<HTMLSpanElement>루트 &lt;span&gt;으로 전달되는 ref (React 19 ref-as-prop)

접근성#

  • 제거 버튼은 네이티브 <button> + aria-label(기본 ‘제거’) — 라벨이 여러 개일 때는 removeLabel="React 태그 제거"처럼 대상을 명시하세요
  • 제거 버튼은 시각은 작지만 ::after히트 영역이 44px까지 확장됩니다(버튼 박스 20px → 44px)
  • :focus-visible 2px focus-ring 링, 아이콘은 장식(aria-hidden 처리된 CloseIcon)
  • 잉크는 *-text 토큰 — AA 대비 빌드 게이트 보장

토큰#

component 토큰 없이 semantic을 직접 소비합니다(신설 기준 §4 미충족).

속성토큰
neutralcolor.surface-muted + color.text-muted
primarycolor.primary-subtle + color.primary-text
success/warning/errorbase 색 8% color-mix 틴트 + color.*-text
형태radius.full · space.1/2/3
타이포font-size.caption(sm) / font-size.body-2(md) + font-weight.medium
제거 버튼icon.size-sm/md · 눌림 color.surface-pressed · duration.fast + ease.standard