Badge#
상태, 카운트, 라벨을 표시하는 배지 컴포넌트입니다.
Live Preview#
class BadgePrimaryExample extends StatefulComponent {
const BadgePrimaryExample({super.key});
@override
State<BadgePrimaryExample> createState() => _BadgePrimaryExampleState();
}
class _BadgePrimaryExampleState extends State<BadgePrimaryExample> {
@override
Component build(BuildContext context) {
return CoBadge(
variant: CoreBadgeVariant.primary,
child: text('Primary'),
);
}
}
class BadgePrimaryExample extends StatefulWidget {
const BadgePrimaryExample({super.key});
@override
State<BadgePrimaryExample> createState() => _BadgePrimaryExampleState();
}
class _BadgePrimaryExampleState extends State<BadgePrimaryExample> {
@override
Widget build(BuildContext context) {
return CoBadge(
variant: CoreBadgeVariant.primary,
child: const Text('Primary'),
);
}
}
class BadgeSecondaryExample extends StatefulComponent {
const BadgeSecondaryExample({super.key});
@override
State<BadgeSecondaryExample> createState() => _BadgeSecondaryExampleState();
}
class _BadgeSecondaryExampleState extends State<BadgeSecondaryExample> {
@override
Component build(BuildContext context) {
return CoBadge(
variant: CoreBadgeVariant.secondary,
child: text('Secondary'),
);
}
}
class BadgeSecondaryExample extends StatefulWidget {
const BadgeSecondaryExample({super.key});
@override
State<BadgeSecondaryExample> createState() => _BadgeSecondaryExampleState();
}
class _BadgeSecondaryExampleState extends State<BadgeSecondaryExample> {
@override
Widget build(BuildContext context) {
return CoBadge(
variant: CoreBadgeVariant.secondary,
child: const Text('Secondary'),
);
}
}
class BadgeDestructiveExample extends StatefulComponent {
const BadgeDestructiveExample({super.key});
@override
State<BadgeDestructiveExample> createState() =>
_BadgeDestructiveExampleState();
}
class _BadgeDestructiveExampleState extends State<BadgeDestructiveExample> {
@override
Component build(BuildContext context) {
return CoBadge(
variant: CoreBadgeVariant.destructive,
child: text('Destructive'),
);
}
}
class BadgeDestructiveExample extends StatefulWidget {
const BadgeDestructiveExample({super.key});
@override
State<BadgeDestructiveExample> createState() =>
_BadgeDestructiveExampleState();
}
class _BadgeDestructiveExampleState extends State<BadgeDestructiveExample> {
@override
Widget build(BuildContext context) {
return CoBadge(
variant: CoreBadgeVariant.destructive,
child: const Text('Destructive'),
);
}
}
class BadgeOutlineExample extends StatefulComponent {
const BadgeOutlineExample({super.key});
@override
State<BadgeOutlineExample> createState() => _BadgeOutlineExampleState();
}
class _BadgeOutlineExampleState extends State<BadgeOutlineExample> {
@override
Component build(BuildContext context) {
return CoBadge(
variant: CoreBadgeVariant.outline,
child: text('Outline'),
);
}
}
class BadgeOutlineExample extends StatefulWidget {
const BadgeOutlineExample({super.key});
@override
State<BadgeOutlineExample> createState() => _BadgeOutlineExampleState();
}
class _BadgeOutlineExampleState extends State<BadgeOutlineExample> {
@override
Widget build(BuildContext context) {
return CoBadge(
variant: CoreBadgeVariant.outline,
child: const Text('Outline'),
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 항목의 상태를 시각적으로 표시할 때 (신규, 완료, 오류 등)
- 알림 카운트를 아이콘에 부착할 때
- 카테고리나 태그를 간결하게 라벨링할 때
대신 다른 컴포넌트를 사용하세요:
Chip: 삭제 가능하거나 클릭 가능한 태그일 때Alert: 더 많은 내용을 포함하는 인라인 알림일 때Toast: 일시적 피드백 메시지일 때
기본 사용법 (Basic Usage)#
// 기본 배지
CoBadge(
variant: CoreBadgeVariant.primary,
child: Text('Primary'),
)
// Secondary 변형
CoBadge(
variant: CoreBadgeVariant.secondary,
child: Text('Secondary'),
)
// Outline 변형
CoBadge(
variant: CoreBadgeVariant.outline,
child: Text('Outline'),
)
// Destructive 변형
CoBadge(
variant: CoreBadgeVariant.destructive,
child: Text('Destructive'),
)
// 기본 배지
CoBadge(
variant: CoreBadgeVariant.primary,
child: text('Primary'),
)
// Secondary 변형
CoBadge(
variant: CoreBadgeVariant.secondary,
child: text('Secondary'),
)
// Outline 변형
CoBadge(
variant: CoreBadgeVariant.outline,
child: text('Outline'),
)
// Destructive 변형
CoBadge(
variant: CoreBadgeVariant.destructive,
child: text('Destructive'),
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
variant |
CoreBadgeVariant |
required | 배지 변형 (primary, secondary, outline, destructive) |
child |
Widget / Component |
required | 배지 콘텐츠 |
size |
CoreComponentSize |
sm |
배지 크기 (xs, sm, md, lg, xl) |
leading |
Widget? / Component? |
null |
앞쪽 아이콘 |
trailing |
Widget? / Component? |
null |
뒤쪽 아이콘 |
onPressed |
VoidCallback? / CoreVoidCallback? |
null |
클릭 콜백 (설정 시 인터랙티브) |
badgeStyle |
CoreBadgeStyle<Color>? / CoreBadgeStyle<CoreColor>? |
null |
인스턴스 스타일 (Style 시스템 참조) |
스타일 시스템 (Style System)#
Badge 의 모든 chrome / dimensional / nested-slot 오버라이드는 CoreBadgeStyle<Clr> 단일 슬롯으로 흐릅니다 (Epic #1302 원칙 6/7/8). 시맨틱 enum (variant,
size) 과 behaviour (child / leading / trailing / onPressed) 는 위젯 파라미터로 직접 전달합니다.
시맨틱 vs 스타일#
-
시맨틱 enum / behaviour: 위젯/컴포넌트 파라미터로 직접 (
variant,size,child,leading,trailing,onPressed) -
chrome / dimensional / 슬롯 스타일:
CoreBadgeStyle한 곳으로 (backgroundColor/foregroundColor/borderColor/borderWidth/borderRadius/paddingH/paddingV/gap/labelStyle/iconStyle)
Resolve chain#
design system default for badge
→ CoreBadgeTheme.style // 프로젝트 공통
→ parent component slot override
→ widget.badgeStyle // 인스턴스별
각 nested 슬롯 스타일 (labelStyle / iconStyle) 은 자기 컴포넌트의 자체 resolve chain 으로 다시 한 번 머지됩니다.
슬롯 매핑 (CoreBadgeStyle 10 필드)#
| 필드 | 타입 (Flutter) | 적용 영역 |
|---|---|---|
backgroundColor |
Color? |
배지 배경 색 (variant 기본값 위에 오버라이드) |
foregroundColor | Color? | 라벨 / 아이콘 전경 색 |
borderColor |
Color? |
보더 색 (outline variant 기본값 오버라이드) |
borderWidth | double? | 보더 두께 (px) |
borderRadius |
double? |
모서리 반지름 (px). null → CoreRadius.radius9999 |
paddingH | double? | 좌/우 패딩 (px) |
paddingV | double? | 위/아래 패딩 (px) |
gap | double? | leading / label / trailing 간격 (px) |
labelStyle |
CoreTextStyle<Color>? |
라벨 텍스트 (자식 텍스트) 스타일 |
iconStyle |
CoreIconStyle<Color>? |
leading / trailing 아이콘 스타일 (양쪽 동시) |
Migration — 옛 평면 chrome → 새 위치 매핑#
기존 CoBadge 는 chrome 평면 필드가 없었습니다 — 모든 chrome 은 CoreBadgeVariantStyle / CoreBadgeTokens
토큰에서만 올라왔습니다. badgeStyle 슬롯이 추가되어 인스턴스 단위로 다음 오버라이드가 가능해졌습니다:
| 기존 (불가능) | 새 위치 |
|---|---|
| 인스턴스 배경색 오버라이드 | badgeStyle.backgroundColor |
| 인스턴스 패딩 오버라이드 | badgeStyle.paddingH / paddingV |
| 인스턴스 모서리 반지름 | badgeStyle.borderRadius |
| 인스턴스 라벨 텍스트 스타일 | badgeStyle.labelStyle |
| 인스턴스 아이콘 사이즈/색 | badgeStyle.iconStyle |
사용 예 (Flutter)#
CoBadge(
variant: CoreBadgeVariant.primary,
badgeStyle: CoreBadgeStyle(
paddingH: 16,
paddingV: 4,
borderRadius: 8,
labelStyle: CoreTextStyle(fontSize: 14, fontWeight: 600),
iconStyle: CoreIconStyle(size: 16),
),
leading: Icon(Icons.star),
child: Text('Featured'),
)
사용 예 (Web)#
CoBadge(
variant: CoreBadgeVariant.primary,
badgeStyle: CoreBadgeStyle<CoreColor>(
paddingH: 16,
paddingV: 4,
borderRadius: 8,
),
leading: CoIcon(CoLucideIcons.star),
child: text('Featured'),
)
변형 (Variants)#
스타일#
CoBadge(variant: CoreBadgeVariant.primary, child: Text('Primary'))
CoBadge(variant: CoreBadgeVariant.secondary, child: Text('Secondary'))
CoBadge(variant: CoreBadgeVariant.outline, child: Text('Outline'))
CoBadge(variant: CoreBadgeVariant.destructive, child: Text('Destructive'))
Leading / Trailing 아이콘#
CoBadge(
variant: CoreBadgeVariant.primary,
leading: Icon(Icons.star),
child: Text('Featured'),
)
CoBadge(
variant: CoreBadgeVariant.secondary,
trailing: Icon(Icons.arrow_forward),
child: Text('Next'),
)
동작 스펙 (Behavior)#
표시#
- 배지는 정적 인디케이터로, 기본적으로 인터랙션 없음
onPressed가 있으면 클릭 가능한 배지 (버튼 동작)- Flutter:
GestureDetector+MouseRegion래핑 - Web:
role="button"+tabindex="0"속성 추가
토큰 기반 스타일링#
CoBadge는 coui_core의 CoreBadgeVariantStyle을 사용하여 크로스 플랫폼 일관된 스타일링을 제공합니다.
| 토큰 | 값 | 설명 |
|---|---|---|
CoreBadgeTokens.borderRadius |
CoreRadius.round (9999px) |
원형 모서리 |
CoreBadgeTokens.borderWidth |
CoreBorderWidth.thin (1px) |
Outline 보더 |
CoreBadgeTokens.paddingH | 10px | 수평 패딩 |
CoreBadgeTokens.paddingV | 2px | 수직 패딩 |
CoreBadgeTokens.gap | 4px | leading/trailing 간격 |
CoreBadgeTokens.iconSize | 12px | 아이콘 크기 |
사용 가이드라인 (Usage Guidelines)#
Do#
상태에 맞는 변형을 사용하세요.
CoBadge(variant: CoreBadgeVariant.primary, child: Text('활성'))
CoBadge(variant: CoreBadgeVariant.destructive, child: Text('오류'))
CoBadge(variant: CoreBadgeVariant.secondary, child: Text('대기'))
색상으로 상태를 즉시 구분할 수 있습니다.
Don't#
모든 배지에 같은 변형을 사용하지 마세요.
CoBadge(variant: CoreBadgeVariant.secondary, child: Text('활성'))
CoBadge(variant: CoreBadgeVariant.secondary, child: Text('오류'))
CoBadge(variant: CoreBadgeVariant.secondary, child: Text('대기'))
상태 구분이 불가능해집니다.
Do#
배지 텍스트는 짧게 유지하세요.
CoBadge(variant: CoreBadgeVariant.primary, child: Text('신규'))
CoBadge(variant: CoreBadgeVariant.secondary, child: Text('Beta'))
한두 단어로 간결하게 표현합니다.
Don't#
배지에 긴 텍스트를 넣지 마세요.
CoBadge(variant: CoreBadgeVariant.primary, child: Text('새로 추가된 기능입니다'))
배지는 간결한 라벨에 적합합니다.
접근성 (Accessibility)#
스크린 리더#
- Flutter: Semantics로 배지 텍스트와 상태 전달
- Web: 배지 텍스트가 인라인으로 읽힘.
onPressed설정 시role="button"자동 부여
색상 대비#
- 모든 변형은 WCAG AA 기준의 텍스트 대비 충족
- 색상만으로 상태를 구분하지 않고 텍스트 라벨도 함께 제공
크로스 플랫폼 차이점 (Platform Differences)#
| 항목 | Flutter | Web |
|---|---|---|
| API | CoBadge(variant: CoreBadgeVariant.*) |
CoBadge(variant: CoreBadgeVariant.*) |
| 스타일링 | CoreBadgeVariantStyle + Theme |
CoreBadgeVariantStyle + Tailwind CSS |
| 인터랙션 | GestureDetector + MouseRegion |
click 이벤트 + role="button" |
| 텍스트 스타일 | typography.labelSmall |
ts.labelSmall Tailwind class |
| 스케일링 | theme.scaling 지원 | 고정 크기 |