Tag | CoUI
본문으로 건너뛰기
LogoCoUI

Tag

태그 — 무엇을 어느 분류에 넣는지 분류색으로 보여 주는 짧은 라벨

목차

Tag 는 항목을 어느 분류에 넣는지 말하는 짧은 라벨입니다. 색은 분류색(CoreCategoryColor) 아홉 가지 중 하나이고, 세기는 옅은 바탕에 선을 두른 subtle 과 채운 bold 두 가지입니다. 표시 전용이라 누를 수 없고, 상태 · 포커스도 없습니다 — 사람이 누르거나 지우는 라벨은 Chip, 상태를 말하는 라벨은 Badge 입니다.

기본 사용법 (Basic Usage)#

Tag(color: CoreCategoryColor.blue, child: Text('디자인'))

Tag(
  color: CoreCategoryColor.green,
  emphasis: CoreTagEmphasis.bold,
  size: CoreTagSize.sm,
  child: Text('새 글'),
)
Tag(color: CoreCategoryColor.blue, child: Text('디자인'))

Tag(
  color: CoreCategoryColor.green,
  emphasis: CoreTagEmphasis.bold,
  size: CoreTagSize.sm,
  child: Text('새 글'),
)

child 에 넘긴 Text 는 태그가 정한 글자 역할(md 는 labelSmall, sm 은 labelXs)과 분류색의 글자색으로 그려지고, 한 줄로 놓입니다. 색을 정하지 않은 태그는 gray 입니다 — 정하지 않은 분류를 어떤 색이 주장하지 않게 합니다.

Live Preview#

구조 (Anatomy)#

 ┌─────────────┐
 │  label      │   child
 └─────────────┘
   box            background · border (subtle)
부분역할슬롯
상자 단의 높이(24 · 20)만큼의 면. subtle 은 분류색의 컨테이너 바탕에 안쪽 1px 선, bold 는 분류색 채움
라벨상자 가운데에 한 줄로 놓이는 글자 — 단의 글자 역할과 분류색의 글자색으로 그려집니다child

Figma: ❖ Tag

Figma 속성 대응#

Figma코드비고
Color (red … gray) color CoreCategoryColor 와 같은 순서 · 이름
Emphasis (subtle · bold) emphasis
Size (md · sm)size
Child (텍스트)child코드는 텍스트가 아니라 위젯을 받습니다

사용 시기 (When to Use)#

이 컴포넌트를 사용하세요:

  • 글 · 일정 · 상품 같은 항목이 어느 분류에 속하는지 보여 줄 때
  • 표의 칸이나 목록의 한 줄 안에서 분류를 색으로 구별할 때

대신 다른 컴포넌트를 사용하세요:

  • Badge: 진행 중 · 완료 · 오류처럼 상태를 말할 때 — 색이 뜻(성공 · 경고)을 가집니다
  • Chip: 사람이 누르거나, 고르거나, 지우는 라벨

Props / Parameters#

W 는 Flutter의 Widget / Web의 Jaspr Component입니다.

속성타입기본값설명
childW필수라벨 — 보통 Text
color CoreCategoryColor CoreTagContract.defaultColor(gray) 분류색 아홉 가지 중 하나
emphasis CoreTagEmphasis CoreTagEmphasis.defaultEmphasis(subtle) 세기 — subtle(옅은 바탕 + 선) · bold(채움)
size CoreTagSize CoreTagSize.defaultSize(md) 단 — md(24) · sm(20)
tagStyle CoreTagStyle? null 모든 chrome 이 지나는 단일 슬롯 (아래 표 참고)

CoreTagStyle 필드#

필드타입설명
backgroundColor CoreColor? Fill colour override. null defers to the hue's colour for the emphasis ([CoreTagStyle.resting]).
foregroundColor CoreColor? Label colour override. null defers to the hue's colour for the emphasis.
borderColor CoreColor? Border stroke colour. null defers to the hue, which states one only for [CoreTagEmphasis.subtle]; with no colour no border is drawn.
borderWidth double? Border stroke width (logical px). null defers to [defaultBorderWidth].
borderRadius CoreBorderRadius? Border radius. null defers to the step's corner in [defaultsBySize].
padding CoreEdgeInsets? Padding around the label. null defers to CoreTagStyle.defaultsBySize[size]!.padding! . Horizontal only by default — the height is [minHeight].
minHeight double? Height of the tag (logical px); the label is centred in it. null defers to CoreTagStyle.defaultsBySize[size]!.minHeight! .
labelStyle CoreTextStyle? Label text style override. null defers to the step's role in [defaultsBySize] with the emphasis's weight from [defaultsByEmphasis] laid over it.

스타일 시스템 (Style System)#

tagStyle#

  • 시맨틱: 위젯 파라미터로 직접 (color · emphasis · size)
  • chrome / dimensional: CoreTagStyle 한 곳으로 (채움 · 글자색 · 선 · 모서리 · 여백 · 높이 · 라벨 글자)
부분필드mdsm
높이minHeight2420
여백padding좌우 8좌우 6
모서리borderRadius64
라벨 labelStyle labelSmall labelXs
선 borderWidth 1 (subtle 만) 1 (subtle 만)

색은 분류색 하나의 다섯 슬롯에서 옵니다.

세기채움글자선라벨 굵기
subtle category-{c}-container on-category-{c}-container category-{c}-outline 역할 그대로(500)
bold category-{c} on-category-{c} 없음 600

라이트 모드에서 outline 슬롯은 컨테이너와 같은 톤이라 선이 보이지 않고, 다크 · 고대비 모드에서 드러납니다. 이건 팔레트의 진술이고 태그가 따로 다루는 경우가 아닙니다.

Resolve chain#

CoreTagStyle.defaultsBySize[size]
  → CoreTagStyle.defaultsByEmphasis[emphasis]
  → CoreTagStyle.resting(color, emphasis)       // 분류색 × 세기의 색
  → CoreTagTheme.style                          // 프로젝트 공통
  → CoreTagTheme.colorStyles[color]
  → CoreTagTheme.emphasisStyles[emphasis]
  → widget.tagStyle                             // 인스턴스별

테마로 덮어쓰기#

CoreComponentTheme(
  tag: CoreTagTheme(
    style: CoreTagStyle(
      borderRadius: CoreBorderRadius.all(CoreRadius.radius9999),
    ),
    emphasisStyles: {
      CoreTagEmphasis.bold: CoreTagStyle(
        padding: CoreEdgeInsets.symmetric(horizontal: CoreSpace.space10),
      ),
    },
  ),
)

빠른 오버라이드 (Chain)#

이미 만든 Tag 인스턴스에 스타일을 빠르게 덧붙이고 싶다면 withStyle 체인을 쓸 수 있습니다. 생성자의 tagStyle 인자와 동일하게 동작하지만, 이미 구성된 위젯 위에서 바로 이어 쓸 수 있습니다.

class TagChainExample extends StatelessWidget {
  const TagChainExample({super.key});

  @override
  Widget build(BuildContext context) {
    // withStyle full-control — a tweak laid over the hue's colours.
    return const Tag(
      color: CoreCategoryColor.purple,
      child: Text('Rounded'),
    ).withStyle(
      const CoreTagStyle(
        borderRadius: CoreBorderRadius.all(CoreRadius.radius9999),
        padding: CoreEdgeInsets.symmetric(horizontal: CoreSpace.space12),
      ),
    );
  }
}
class TagChainExample extends StatelessComponent {
  const TagChainExample({super.key});

  @override
  Component build(BuildContext context) {
    // withStyle full-control — a tweak laid over the hue's colours.
    return Tag(
      color: CoreCategoryColor.purple,
      child: Text('Rounded'),
    ).withStyle(
      const CoreTagStyle(
        borderRadius: CoreBorderRadius.all(CoreRadius.radius9999),
        padding: CoreEdgeInsets.symmetric(horizontal: CoreSpace.space12),
      ),
    );
  }
}

변형 (Variants)#

분류색#

아홉 가지 — red · orange · yellow · green · blue · purple · pink · brown · gray. 색에는 상태의 뜻이 없습니다. 같은 분류에는 화면 어디서나 같은 색을 씁니다.

emphasis: bold#

분류색 채움 위에 on 색 글자, 선 없음, 라벨은 600. 한 줄의 태그 중 하나만 눈에 띄어야 할 때 씁니다.

Tag(
  color: CoreCategoryColor.red,
  emphasis: CoreTagEmphasis.bold,
  child: Text('긴급'),
)

size: sm#

20px 단 — 표의 칸이나 목록의 한 줄처럼 촘촘한 자리에 씁니다. 기본 md 는 24px 로 상태 배지와 같은 높이입니다.

Tag(color: CoreCategoryColor.blue, size: CoreTagSize.sm, child: Text('디자인'))

동작 스펙 (Behavior)#

배치#

  • 상자는 단의 높이 이상이고, 라벨은 상자의 가로 · 세로 가운데에 한 줄로 놓입니다 — 줄바꿈하지 않습니다
  • 폭은 라벨이 정합니다(좌우 여백 + 라벨 폭)
  • 선은 상자 안쪽에 그려져 높이를 늘리지 않습니다

인터랙션#

  • 없습니다. 누름 · hover · pressed 상태가 없고 포커스를 받지 않습니다

상태 전환#

  • 상태가 없습니다. 같은 color · emphasis · size 면 같은 그림입니다

애니메이션#

  • 없습니다

재질#

활성 테마의 서피스 스타일이 재질을 가지면, 채움을 칠하는 태그는 내용 표면(content)으로 그 재질을 입습니다. 재질이 없는 기본 상태에서는 불투명한 채움 하나입니다.

사용 가이드라인 (Usage Guidelines)#

Do#

한 분류에는 한 색

Tag(color: CoreCategoryColor.blue, child: Text('디자인'))
Tag(color: CoreCategoryColor.green, child: Text('개발'))

이유: 색이 분류의 이름표 역할을 하려면 같은 분류가 어디서나 같은 색이어야 합니다.

Don't#

상태를 태그로 말하지 않는다

// ❌ 분류색에는 성공 · 오류의 뜻이 없다
Tag(color: CoreCategoryColor.red, child: Text('실패'))

// ✅ 상태는 Badge
Badge(tone: CoreBadgeTone.destructive, child: Text('실패'))

이유: 분류색은 고대비 · 다크 모드에서도 상태 색과 짝을 맞추지 않습니다. 상태는 상태 토큰을 쓰는 Badge 가 말합니다.

접근성 (Accessibility)#

역할#

  • Flutter: 따로 Semantics 를 달지 않습니다 — 라벨 Text 가 그대로 읽힙니다
  • Web: role 없는 <span> 입니다

키보드#

키FlutterWeb
Tab지나치지 않음 — 포커스를 받지 않습니다지나치지 않음 — 포커스를 받지 않습니다

스크린 리더#

이름은 child 의 텍스트에서 나옵니다. 색은 읽히지 않으므로, 색만으로 분류를 구별하지 말고 라벨 낱말이 분류를 말하게 합니다.

포커스 관리#

  • 진입 · 이탈 · 트랩: 없음

알려진 제약#

  • 아이콘 슬롯이 없습니다 — 라벨은 child 하나입니다
  • 라이트 모드의 subtle 선은 보이지 않습니다(팔레트의 outline 슬롯이 컨테이너와 같은 톤)

전역 축(동작 줄이기 · 고대비 · 색 강제 모드 · 시맨틱 역할 · 최소 터치 타겟)은 접근성 페이지가 한 곳에서 다룹니다.

크로스 플랫폼 차이점 (Platform Differences)#

child / color / emphasis / size / tagStyle 은 양 플랫폼 동일 API 입니다.

항목FlutterWeb
루트 Container(채움 + 선) → 가운데 맞춘 Row <span> — inline-flex, 가운데 맞춤, 줄바꿈 없음
높이 BoxConstraints(minHeight) min-h-* 클래스(크기 스케일 변수), 덮어쓴 값은 inline min-height
선 Border.all — 선 색이 있을 때만 border-width — 선 색이 있을 때만
라벨 글자 DefaultTextStyle.merge 로 역할 · 굵기 · 색 설치 text-{role} 클래스 + 굵기 inline
chrome emit paint-ready BoxDecoration / TextStyle Tailwind class + inline CSS
Web 전용 HTML 표면 — attributes · classes · css · eventHandlers · id 통과
  • Badge: 상태를 말하는 라벨
  • Chip: 누르거나 고르거나 지우는 라벨

조합 예제#

Row(
  spacing: CoreSpace.space8,
  children: [
    Text('디자인 시스템 개편').titleSmall,
    Tag(color: CoreCategoryColor.blue, size: CoreTagSize.sm, child: Text('디자인')),
    Tag(color: CoreCategoryColor.green, size: CoreTagSize.sm, child: Text('개발')),
  ],
)