Breadcrumb#
현재 페이지의 위치를 계층적으로 표시하여 사용자가 상위 페이지로 쉽게 이동할 수 있도록 하는 탐색 경로 컴포넌트입니다.
Live Preview#
Breadcrumb(
items: [
BreadcrumbItem(label: 'Home', href: '/'),
BreadcrumbItem(label: 'Components'),
BreadcrumbItem(label: 'Current', isActive: true),
],
)
Breadcrumb(
children: [
TextButton(onPressed: () {}, child: Text('Home')),
TextButton(onPressed: () {}, child: Text('Components')),
Text('Breadcrumb'),
],
)
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 3단계 이상의 계층 구조를 가진 페이지에서 현재 위치를 안내할 때
- 사용자가 상위 카테고리로 빠르게 돌아갈 수 있어야 할 때 (예: 이커머스 카테고리, 관리자 설정)
- 문서, 파일 탐색기처럼 깊은 계층 구조를 탐색할 때
대신 다른 컴포넌트를 사용하세요:
Tabs: 동일 레벨의 섹션을 전환할 때Navigation: 앱 주요 섹션 간 이동에는 네비게이션 사용Link: 단순 이전 페이지 이동 링크만 필요할 때
기본 사용법 (Basic Usage)#
// 기본 브레드크럼
Breadcrumb(
items: [
BreadcrumbItem(label: '홈', onTap: handleHomeNavigation),
BreadcrumbItem(label: '카테고리', onTap: handleCategoryNavigation),
BreadcrumbItem(label: '상품 목록', onTap: handleProductListNavigation),
BreadcrumbItem(label: '상품 상세'),
],
)
// 커스텀 구분자
Breadcrumb(
items: [
BreadcrumbItem(label: '설정', onTap: handleSettingsNavigation),
BreadcrumbItem(label: '계정', onTap: handleAccountNavigation),
BreadcrumbItem(label: '보안'),
],
separator: const Icon(Icons.chevron_right, size: 16),
)
// 최대 항목 수 제한 (중간 생략)
Breadcrumb(
items: deepNavigationPath,
maxItems: 3,
onItemTap: handleBreadcrumbNavigation,
)
// 기본 브레드크럼 (href로 링크 처리)
Breadcrumb(
items: [
BreadcrumbItem(label: '홈', href: '/'),
BreadcrumbItem(label: '카테고리', href: '/category'),
BreadcrumbItem(label: '상품 상세', isActive: true),
],
)
// 커스텀 구분자 (문자열 separator)
Breadcrumb(
separator: '>',
items: [
BreadcrumbItem(label: '설정', href: '/settings'),
BreadcrumbItem(label: '계정', href: '/settings/account'),
BreadcrumbItem(label: '보안', isActive: true),
],
)
// 깊은 계층 (최대 항목 수 — isActive로 현재 페이지 표시)
Breadcrumb(
separator: '›',
items: [
BreadcrumbItem(label: '대시보드', href: '/'),
BreadcrumbItem(label: '프로젝트', href: '/projects'),
BreadcrumbItem(label: 'CoUI', href: '/projects/coui'),
BreadcrumbItem(label: '이슈 목록', isActive: true),
],
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
items |
List<BreadcrumbItem> |
필수 | 탐색 경로 항목 목록 |
separator |
Widget? |
null |
항목 구분자 위젯 |
maxItems |
int? |
null |
최대 표시 항목 수 (초과 시 생략) |
onItemTap |
void Function(BreadcrumbItem)? |
null |
항목 탭 콜백 |
breadcrumbStyle |
CoreBreadcrumbStyle<Color>? / CoreBreadcrumbStyle<CoreColor>? |
null |
인스턴스 스타일 (Style 시스템 참조) |
스타일 시스템 (Style System)#
Breadcrumb 의 모든 chrome / dimensional / nested-slot 오버라이드는 CoreBreadcrumbStyle<Clr>
단일 슬롯으로 흐릅니다 (Epic #1302 원칙 6/7/8). 시맨틱 / behaviour 필드 (items / separator /
padding) 는 위젯/컴포넌트 파라미터로 직접 전달합니다.
시맨틱 vs 스타일#
-
시맨틱 / behaviour: 위젯/컴포넌트 파라미터로 직접 (
items,separator,padding,children) -
chrome / dimensional / 슬롯 스타일:
CoreBreadcrumbStyle한 곳으로 (gap/currentItemColor/itemTextStyle/separatorIconStyle)
Resolve chain#
design system default for breadcrumb
→ CoreBreadcrumbTheme.style // 프로젝트 공통
→ parent component slot override
→ widget.breadcrumbStyle // 인스턴스별
각 nested 슬롯 스타일 (itemTextStyle / separatorIconStyle) 은 자기 컴포넌트의 자체 resolve chain 으로 다시 한 번 머지됩니다.
슬롯 매핑 (CoreBreadcrumbStyle 4 필드)#
| 필드 | 타입 (Flutter) | 적용 영역 |
|---|---|---|
gap | double? | item / separator / item 간격 (px) |
currentItemColor | Color? | 현재(마지막) 항목 — 비탐색 라벨 색 |
itemTextStyle |
CoreTextStyle<Color>? |
모든 breadcrumb 항목 텍스트 스타일 |
separatorIconStyle |
CoreIconStyle<Color>? |
화살표/슬래시 separator 아이콘 스타일 |
Migration#
기존 BreadcrumbTheme 의 평면 chrome (padding / separator) 은 호환을 위해 유지되지만, 새 코드는
breadcrumbStyle 슬롯을 사용하세요:
| 기존 (legacy theme 필드) | 새 위치 |
|---|---|
BreadcrumbTheme.padding |
위젯 padding 파라미터 또는 부모 레이아웃 wrapper |
| 인스턴스 항목 텍스트 색 (불가능) | breadcrumbStyle.itemTextStyle.color |
| 인스턴스 항목 텍스트 사이즈 (불가능) | breadcrumbStyle.itemTextStyle.fontSize |
| 인스턴스 separator 아이콘 색 (불가능) | breadcrumbStyle.separatorIconStyle.color |
| 현재 항목 강조 색 (불가능) | breadcrumbStyle.currentItemColor |
| 항목 간격 (불가능) | breadcrumbStyle.gap |
사용 예 (Flutter)#
Breadcrumb(
children: [
Text('Home'),
Text('Products'),
Text('Laptop'),
],
breadcrumbStyle: CoreBreadcrumbStyle(
gap: 8,
currentItemColor: Colors.blue,
itemTextStyle: CoreTextStyle(fontSize: 14, color: Colors.grey),
),
)
사용 예 (Web)#
Breadcrumb(
items: [
BreadcrumbItem(label: 'Home', href: '/'),
BreadcrumbItem(label: 'Products', href: '/products'),
BreadcrumbItem(label: 'Laptop', isActive: true),
],
breadcrumbStyle: CoreBreadcrumbStyle<CoreColor>(
gap: 8,
),
)
변형 (Variants)#
기본 (슬래시 구분자)#
Breadcrumb(
items: [
BreadcrumbItem(label: '대시보드', onTap: handleDashboardNavigation),
BreadcrumbItem(label: '프로젝트', onTap: handleProjectNavigation),
BreadcrumbItem(label: 'CoUI'),
],
)
화살표 구분자#
Breadcrumb(
items: pagePath,
separator: const Icon(Icons.arrow_forward_ios, size: 12),
)
동작 스펙 (Behavior)#
인터랙션#
- 클릭/탭:
onTap이 설정된 항목 클릭 시 해당 콜백 호출 (마지막 항목은 현재 페이지이므로 비활성) - 호버: 클릭 가능한 항목 호버 시 언더라인 표시
- 생략 처리:
maxItems초과 시 중간 항목을...으로 축소; 클릭 시 전체 경로 펼침
상태 전환#
- 마지막 항목은 현재 위치를 나타내며 비활성 텍스트로 표시
- 앞 항목들은 링크 스타일로 표시 (클릭 가능)
애니메이션#
- 생략된 항목 펼침 시 200ms ease-in-out 확장 애니메이션
사용 가이드라인 (Usage Guidelines)#
✅ Do#
현재 페이지(마지막 항목)는 클릭 불가로 표시
CouiBreadcrumb(
items: [
BreadcrumbItem(label: '홈', onTap: handleHomeNavigation),
BreadcrumbItem(label: '설정', onTap: handleSettingsNavigation),
BreadcrumbItem(label: '보안'), // onTap 없음 = 현재 페이지
],
)
현재 페이지로의 이동은 무의미하므로 비활성 처리가 UX를 명확히 한다.
❌ Don't#
2단계 이하 계층에서 브레드크럼 남용하지 않기
// ❌ 단순 2단계 구조에 브레드크럼
CouiBreadcrumb(
items: [
BreadcrumbItem(label: '홈', onTap: handleHomeNavigation),
BreadcrumbItem(label: '설정'),
],
)
2단계 이하는 뒤로가기 버튼 또는 간단한 Link로 충분하며 브레드크럼이 오히려 복잡도를 높인다.
✅ Do#
항목이 많을 때 maxItems로 가운데 항목 생략
CouiBreadcrumb(
items: deepPath,
maxItems: 4, // 처음 1개 + ... + 마지막 2개 표시
)
긴 경로를 모두 표시하면 좁은 화면에서 줄바꿈이 발생해 레이아웃을 해친다.
❌ Don't#
구분자를 지나치게 화려하게 커스텀하지 않기
// ❌ 너무 큰 구분자 아이콘
CouiBreadcrumb(
items: path,
separator: const Icon(Icons.double_arrow, size: 32),
)
구분자는 보조 역할이므로 작고 단순하게 유지해야 경로 텍스트에 시선이 집중된다.
✅ Do#
구분자는 시각적으로 명확하게 표시하세요.
CouiBreadcrumb(
items: [
BreadcrumbItem(label: '홈', onTap: handleHomeNavigation),
BreadcrumbItem(label: '상품', onTap: handleProductNavigation),
BreadcrumbItem(label: '전자기기', onTap: handleElectronicsNavigation),
BreadcrumbItem(label: '노트북'),
],
separator: Icon(Icons.chevron_right, size: 16),
)
명확한 구분자는 계층 구조를 시각적으로 전달하여 현재 위치를 빠르게 파악할 수 있게 합니다.
❌ Don't#
경로가 너무 길어질 때 생략 없이 모두 표시하지 마세요.
// ❌ 7단계 전체 경로 표시 (너무 길어 UI 깨짐)
CouiBreadcrumb(
items: allSevenLevels, // maxItems 생략
)
경로가 길면 maxItems 속성으로 중간 항목을 생략 처리하여 UI가 넘치지 않도록 해야 합니다.
접근성 (Accessibility)#
키보드 인터랙션#
| 키 | 동작 |
|---|---|
Tab | 다음 클릭 가능한 항목으로 포커스 이동 |
Enter | 포커스된 항목 활성화 |
Shift + Tab | 이전 항목으로 포커스 이동 |
스크린 리더#
- Flutter:
Semantics(role: 'navigation', label: '탐색 경로')래핑 -
Web:
<nav aria-label="breadcrumb">자동 적용; 현재 페이지 항목에aria-current="page"추가
터치 타겟#
- 클릭 가능한 항목 최소 터치 타겟: 44x44dp
- 작은 구분자는 터치 영역에 포함하지 않음
크로스 플랫폼 차이점 (Platform Differences)#
| 항목 | Flutter | Web |
|---|---|---|
| 클래스명 | CouiBreadcrumb | Breadcrumb |
| 링크 처리 | onTap 콜백 |
href 속성으로 <a> 태그 렌더링 |
| 구분자 | Widget | 문자열 또는 Widget |
| SEO | 해당 없음 | 구조화된 데이터(JSON-LD) 지원 |
관련 컴포넌트 (Related Components)#
- Navigation: 앱 주요 섹션 간 이동에 사용
- Tabs: 동일 계층의 콘텐츠를 탭으로 전환할 때 사용
- Link: 단일 이전 페이지 이동 링크가 필요할 때 사용
조합 예제#
// 페이지 헤더에 브레드크럼 + 제목 조합
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CouiBreadcrumb(
items: [
BreadcrumbItem(label: '상품 관리', onTap: handleProductListNavigation),
BreadcrumbItem(label: '상품 상세'),
],
),
const Gap.sm(),
Text('CoUI T-Shirt', style: Theme.of(context).textTheme.headlineMedium),
],
)