Breadcrumb | CoUI

Breadcrumb

현재 페이지의 위치를 계층적으로 나타내는 탐색 경로 컴포넌트

Breadcrumb#

현재 페이지의 위치를 계층적으로 표시하여 사용자가 상위 페이지로 쉽게 이동할 수 있도록 하는 탐색 경로 컴포넌트입니다.

Live Preview#

Web
Flutter
Loading Flutter...
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)적용 영역
gapdouble?item / separator / item 간격 (px)
currentItemColorColor?현재(마지막) 항목 — 비탐색 라벨 색
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)#

항목FlutterWeb
클래스명CouiBreadcrumbBreadcrumb
링크 처리 onTap 콜백 href 속성으로 <a> 태그 렌더링
구분자Widget문자열 또는 Widget
SEO해당 없음구조화된 데이터(JSON-LD) 지원
  • 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),
  ],
)