Navigation Bar in Flutter

Implement modern, functional navigation bars in your apps

Download Complete Examples

What is Navigation Bar?

Navigation Bar (also known as Bottom Navigation Bar) is a fundamental widget in Flutter that enables navigation between a mobile application's main sections.

Types of Navigation Bars

Basic Implementation

Scaffold with BottomNavigationBar

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Navigation Bar Example',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  int _selectedIndex = 0;

  static const List<Widget> _pages = [
    HomePage(),
    SearchPage(),
    ProfilePage(),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Mi App')),
      body: _pages[_selectedIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _selectedIndex,
        onTap: _onItemTapped,
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            label: 'Find',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}

Main Properties

items

List of navigation elements

Type: List<BottomNavigationBarItem>

Required: Yes

currentIndex

Index of the selected item

Type: int

Required: Yes

onTap

Function called when an item is tapped

Type: ValueChanged<int>

Required: Yes

backgroundColor

The bar's background color

Type: Color

Default: Theme.bottomAppBarColor

selectedItemColor

Color of the selected item

Type: Color

Default: Theme.primaryColor

unselectedItemColor

Color of unselected items

Type: Color

Default: Theme.unselectedWidgetColor

BottomNavigationBarItem

icon

Item icon (required)

icon: Icon(Icons.home)

label

Item text (required)

label: 'Home'

activeIcon

Icon when active (optional)

activeIcon: Icon(Icons.home_filled)

backgroundColor

Background color for the item (optional)

backgroundColor: Colors.blue

Complete Items Example:

BottomNavigationBar(
  items: const [
    BottomNavigationBarItem(
      icon: Icon(Icons.home_outlined),
      activeIcon: Icon(Icons.home),
      label: 'Home',
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.search_outlined),
      activeIcon: Icon(Icons.search),
      label: 'Find',
      backgroundColor: Colors.green,
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.person_outline),
      activeIcon: Icon(Icons.person),
      label: 'Profile',
    ),
  ],
)

Visual Examples

1. Navigation Bar Classic

BottomNavigationBar(
  currentIndex: _selectedIndex,
  onTap: _onItemTapped,
  items: const [
    BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
    BottomNavigationBarItem(icon: Icon(Icons.shop), label: 'Tienda'),
    BottomNavigationBarItem(icon: Icon(Icons.favorite), label: 'Favorites'),
    BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
  ],
)

2. Navigation Bar with Custom Colors

BottomNavigationBar(
  backgroundColor: Colors.deepPurple,
  selectedItemColor: Colors.amber,
  unselectedItemColor: Colors.white70,
  currentIndex: _selectedIndex,
  onTap: _onItemTapped,
  items: const [
    BottomNavigationBarItem(icon: Icon(Icons.music_note), label: 'Música'),
    BottomNavigationBarItem(icon: Icon(Icons.podcasts), label: 'Podcasts'),
    BottomNavigationBarItem(icon: Icon(Icons.radio), label: 'Radio'),
  ],
)

3. Navigation Bar with Badges

// Requiere el package: badges: ^2.0.3BottomNavigationBarItem(
  icon: Badge(
    badgeContent: Text('3'),
    child: Icon(Icons.notifications),
  ),
  label: 'Notificaciones',
)

NavigationBar (Material 3)

Flutter introduces a new Navigation Bar implementation with Material Design 3, more modern and flexible.

NavigationBar with Material 3

NavigationBar(
  selectedIndex: _selectedIndex,
  onDestinationSelected: (index) => setState(() => _selectedIndex = index),
  destinations: const [
    NavigationDestination(
      icon: Icon(Icons.home_outlined),
      selectedIcon: Icon(Icons.home),
      label: 'Home',
    ),
    NavigationDestination(
      icon: Icon(Icons.explore_outlined),
      selectedIcon: Icon(Icons.explore),
      label: 'Explorar',
    ),
    NavigationDestination(
      icon: Icon(Icons.person_outlined),
      selectedIcon: Icon(Icons.person),
      label: 'Profile',
    ),
  ],
)
Feature BottomNavigationBar NavigationBar
Design Material Design 2 Material Design 3
Animations Basic Smoother
Customization Limited Extensive
Compatibility All versions Flutter 3.10+

Customizer for Navigation Bar

3 items
Pantalla de Ejemplo

Application content...

// El código se generará aquí

State Management

1. StatefulWidget Basics

Ideal for simple applications with few screens

class _HomeScreenState extends State<HomeScreen> {
  int _selectedIndex = 0;
  
  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _selectedIndex,
        onTap: _onItemTapped,
        items: [...],
      ),
      body: _buildPage(_selectedIndex),
    );
  }
}

2. With Provider (Recommended)

For more complex applications with shared state

class NavigationProvider with ChangeNotifier {
  int _currentIndex = 0;
  
  int get currentIndex => _currentIndex;
  
  void changeIndex(int index) {
    _currentIndex = index;
    notifyListeners();
  }
}

// En el widgetConsumer<NavigationProvider>(
  builder: (context, provider, child) {
    return BottomNavigationBar(
      currentIndex: provider.currentIndex,
      onTap: (index) => provider.changeIndex(index),
      items: [...],
    );
  },
)

Best Practices

✅ What you SHOULD do

  • Use between 3 and 5 items maximum
  • Keep labels short and descriptive
  • Use recognizable icons
  • Implement persistent state between navigations
  • Consider using NavigationBar for new apps

❌ What you should NOT do

  • Don't use more than 5 items
  • Avoid very long labels
  • Don't mix different navigation patterns
  • Don't forget to handle the state correctly
  • Don't use NavigationBar without Material 3

Pro Tip

For an optimal user experience, consider using PageStorage to preserve scroll state and each tab's data as the user navigates between them.

Exercises to Practice

Exercise 1: Music App

Create a music app with navigation between Library, Search and Playlists.

Suggested items: Library, Find, Playlists, Settings

Exercise 2: E-commerce App

Implement an e-commerce app with a cart that shows a badge with the quantity.

Suggested items: Home, Categories, Cart (with badge), Profile

Exercise 3: News App

Create a news app with persistent navigation using Provider.

Suggested items: News, Favorites, Profile, Settings

Common Troubleshooting

❌ The icons don't change color

Solution: Make sure to define selectedItemColor and unselectedItemColor

selectedItemColor: Colors.blue, unselectedItemColor: Colors.grey

❌ The badge doesn't display correctly

Solution: Use the badges package and configure the Badge correctly

Badge(badgeContent: Text('3'), child: Icon(Icons.notifications))

❌ Navigation isn't working

Solution: Verify that currentIndex and onTap are configured

currentIndex: _selectedIndex, onTap: _onItemTapped