NavigationBar | CoUI

NavigationBar

앱 하단에 위치하는 주요 섹션 간 이동을 위한 네비게이션 바 컴포넌트

NavigationBar#

앱의 주요 섹션 간 이동을 위한 하단 네비게이션 바 컴포넌트입니다. 아이콘과 레이블을 조합하여 현재 위치를 시각적으로 표시합니다.

Live Preview#

Web
Flutter
Loading Flutter...
NavigationBar(
  items: [
    NavigationItem(label: 'Home'),
    NavigationItem(label: 'Search'),
    NavigationItem(label: 'Profile'),
  ],
  currentIndex: 0,
)
NavigationBar(
  index: 0,
  onSelected: handleSelected,
  children: [
    NavigationItem(child: Text('Home')),
    NavigationItem(child: Text('Search')),
    NavigationItem(child: Text('Profile')),
  ],
)

사용 시기 (When to Use)#

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

  • 모바일 앱의 주요 3~5개 섹션 간 이동이 필요할 때
  • 사용자가 어느 화면에서든 빠르게 주요 섹션으로 이동할 수 있어야 할 때
  • 현재 선택된 섹션을 항상 표시해야 할 때

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

  • Navigation: 사이드바 형태의 네비게이션이 필요할 때
  • Tabs: 동일 화면 내에서 콘텐츠 탭을 전환할 때
  • Switcher: 보기 모드 전환 등 로컬 전환에

기본 사용법 (Basic Usage)#

// 기본 네비게이션 바
NavigationBar(
  currentIndex: _selectedIndex,
  onTap: handleTabChanged,
  items: [
    NavigationBarItem(
      icon: Icon(Icons.home_outlined),
      activeIcon: Icon(Icons.home),
      label: '홈',
    ),
    NavigationBarItem(
      icon: Icon(Icons.search_outlined),
      activeIcon: Icon(Icons.search),
      label: '검색',
    ),
    NavigationBarItem(
      icon: Icon(Icons.person_outlined),
      activeIcon: Icon(Icons.person),
      label: '프로필',
    ),
  ],
)

// Outlined 변형, 레이블 숨김
NavigationBar(
  currentIndex: _selectedIndex,
  onTap: handleTabChanged,
  variant: NavigationBarVariant.outlined,
  showLabels: false,
  items: [
    NavigationBarItem(icon: Icon(Icons.home_outlined), label: '홈'),
    NavigationBarItem(icon: Icon(Icons.search_outlined), label: '검색'),
    NavigationBarItem(icon: Icon(Icons.settings_outlined), label: '설정'),
  ],
)
NavigationBar(
  currentIndex: _selectedIndex,
  onTap: handleTabChanged,
  items: [
    NavigationBarItem(icon: Icon(Icons.home), label: '홈'),
    NavigationBarItem(icon: Icon(Icons.search), label: '검색'),
    NavigationBarItem(icon: Icon(Icons.person), label: '프로필'),
  ],
)

NavigationBar(
  currentIndex: _selectedIndex,
  onTap: handleTabChanged,
  variant: NavigationBarVariant.outlined,
  showLabels: true,
  items: [
    NavigationBarItem(icon: Icon(Icons.home), label: '홈'),
    NavigationBarItem(icon: Icon(Icons.search), label: '검색'),
  ],
)

Props / Parameters#

속성타입기본값설명
items List<NavigationBarItem> 필수 네비게이션 아이템 목록
currentIndex int 0 현재 선택된 아이템 인덱스
onTap void Function(int)? null 아이템 탭 핸들러
variant NavigationBarVariant filled 스타일 변형
showLabels bool true 레이블 표시 여부
속성타입기본값설명
iconWidget필수비활성 상태 아이콘
activeIcon Widget? null 활성 상태 아이콘 (미지정 시 icon 사용)
labelString필수아이템 레이블 텍스트

변형 (Variants)#

Filled#

배경색이 채워진 기본 변형입니다. 선택된 아이템의 배경이 강조됩니다.

NavigationBar(
  variant: NavigationBarVariant.filled,
  currentIndex: 0,
  onTap: handleTabChanged,
  items: [...],
)

Outlined#

테두리만 있는 변형입니다. 미니멀한 디자인에 적합합니다.

NavigationBar(
  variant: NavigationBarVariant.outlined,
  currentIndex: 0,
  onTap: handleTabChanged,
  items: [...],
)

동작 스펙 (Behavior)#

인터랙션#

  • : 항목 탭 시 onTap(index) 호출
  • 호버: 항목 호버 시 배경색 약한 강조

상태 전환#

  • inactiveactive: 다른 항목 탭 시 현재 항목 활성화, 이전 항목 비활성화
  • activeIcon이 있는 경우 활성 시 아이콘 교체

애니메이션#

  • 활성 항목 전환: 배경색 변경 200ms ease-in-out
  • 아이콘 교체: 크로스 페이드 150ms

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

✅ Do#

항목 수를 3~5개로 제한

CouiNavigationBar(
  currentIndex: _selectedIndex,
  onTap: handleTabChanged,
  items: [
    NavigationBarItem(icon: Icon(Icons.home_outlined), label: '홈'),
    NavigationBarItem(icon: Icon(Icons.explore_outlined), label: '탐색'),
    NavigationBarItem(icon: Icon(Icons.notifications_outlined), label: '알림'),
    NavigationBarItem(icon: Icon(Icons.person_outlined), label: '프로필'),
  ],
)

항목이 너무 많으면 각 아이콘이 너무 작아지고 레이블이 잘린다. 3~5개가 최적이다.


❌ Don't#

6개 이상의 항목을 NavigationBar에 넣지 않기

// ❌ 너무 많은 항목
CouiNavigationBar(
  items: List.generate(7, (i) => NavigationBarItem(
    icon: Icon(Icons.circle),
    label: '메뉴 ${i + 1}',
  )),
  currentIndex: 0,
  onTap: handleTabChanged,
)

항목이 6개를 초과하면 레이블이 잘리거나 아이콘이 너무 작아진다.

✅ Do#

활성/비활성 아이콘을 쌍으로 제공

NavigationBarItem(
  icon: Icon(Icons.home_outlined),    // 비활성: 윤곽선
  activeIcon: Icon(Icons.home),       // 활성: 채움
  label: '홈',
)

채워진 아이콘과 윤곽선 아이콘을 쌍으로 사용하면 선택 상태가 더 명확하게 전달된다.


❌ Don't#

레이블 없이 아이콘만 사용하는 경우 semanticLabel 생략

// ❌ showLabels: false인데 semanticLabel 없음
NavigationBarItem(
  icon: Icon(Icons.home_outlined),
  label: '홈', // showLabels: false라도 label은 접근성에 사용됨
)

showLabels: false여도 label은 스크린 리더용으로 반드시 설정해야 한다.

✅ Do#

네비게이션 바에는 3~5개의 주요 섹션만 배치하세요.

CouiNavigationBar(
  items: [
    NavigationBarItem(icon: Icons.home, label: '홈'),
    NavigationBarItem(icon: Icons.search, label: '검색'),
    NavigationBarItem(icon: Icons.favorite, label: '찜'),
    NavigationBarItem(icon: Icons.person, label: '프로필'),
  ],
  currentIndex: currentTab,
  onChanged: handleTabChanged,
)

3~5개의 주요 섹션이 탐색 구조를 명확하게 유지하고 사용자가 빠르게 이동할 수 있습니다.


❌ Don't#

네비게이션 바에 중요도가 낮은 페이지를 포함하지 마세요.

// ❌ 덜 중요한 페이지까지 네비게이션 바에 포함
CouiNavigationBar(
  items: [
    NavigationBarItem(icon: Icons.home, label: '홈'),
    NavigationBarItem(icon: Icons.settings, label: '설정'),  // 덜 중요
    NavigationBarItem(icon: Icons.info, label: '약관'),     // 거의 안 씀
    NavigationBarItem(icon: Icons.help, label: '도움말'),   // 거의 안 씀
  ],
)

네비게이션 바는 자주 사용하는 핵심 기능에만 사용해야 합니다. 설정이나 도움말은 메뉴나 프로필 화면에서 접근하도록 하세요.

접근성 (Accessibility)#

키보드 인터랙션#

동작
Tab다음 네비게이션 항목으로 포커스
Enter / Space포커스된 항목 활성화
Arrow Left/Right항목 간 이동

스크린 리더#

  • Flutter: Semantics(selected: isActive, label: itemLabel) 자동 적용
  • Web: role="navigation" + aria-label="메인 네비게이션" + 각 항목 aria-current="page" 적용

터치 타겟#

  • 각 항목 최소 터치 타겟: 48x48dp

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

항목FlutterWeb
클래스명CouiNavigationBarNavigationBar
탭 핸들러onTaponTap
위치 Scaffold.bottomNavigationBar 화면 하단 고정 (position: fixed)
배경 블러지원 (BackdropFilter)CSS backdrop-filter
  • Navigation: 사이드바/상단 바 형태의 네비게이션
  • Tabs: 화면 내 콘텐츠 섹션 전환에 사용

조합 예제#

// Scaffold와 NavigationBar 조합
Scaffold(
  body: IndexedStack(
    index: _selectedIndex,
    children: [
      const HomeScreen(),
      const SearchScreen(),
      const ProfileScreen(),
    ],
  ),
  bottomNavigationBar: CouiNavigationBar(
    currentIndex: _selectedIndex,
    onTap: handleTabChanged,
    items: [
      NavigationBarItem(
        icon: Icon(Icons.home_outlined),
        activeIcon: Icon(Icons.home),
        label: '홈',
      ),
      NavigationBarItem(
        icon: Icon(Icons.search_outlined),
        activeIcon: Icon(Icons.search),
        label: '검색',
      ),
      NavigationBarItem(
        icon: Icon(Icons.person_outlined),
        activeIcon: Icon(Icons.person),
        label: '프로필',
      ),
    ],
  ),
)