TabBar in Flutter

Implement elegant, functional tabs in your apps

Download Complete Examples

What is TabBar?

The TabBar is a fundamental widget in Flutter that lets you organize content into horizontal tabs, ideal for showing different sections of an application in an organized way.

Todos
Favorites
Archivados

All Content

List of all elements...

Favorites Content

Elements marked as favorites...

Archived Content

Archived elements...

Main Features:

  • ✅ Efficient content organization
  • ✅ Fast navigation between sections
  • ✅ Consistent design with Material Design
  • ✅ Highly customizable
  • ✅ Perfect integration with TabBarView

Types of TabBars

DefaultTabBar

TabBar standard with a simple indicator

Home
Profile
Config

TabBar Customized

With custom colors, shapes and styles

Música
Podcasts
Radio

Scrollable TabBar

For many tabs with horizontal scrolling

Ene
Feb
Mar
Abr
May

Basic Implementation

DefaultTabController with TabBar

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: 'TabBar Example',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const TabBarExample(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 3,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Mi App con Pestañas'),
          bottom: const TabBar(
            tabs: [
              Tab(icon: Icon(Icons.home), text: 'Home'),
              Tab(icon: Icon(Icons.search), text: 'Find'),
              Tab(icon: Icon(Icons.person), text: 'Profile'),
            ],
          ),
        ),
        body: const TabBarView(
          children: [
            Center(child: Text('Contenido de Inicio')),
            Center(child: Text('Contenido de Búsqueda')),
            Center(child: Text('Contenido de Perfil')),
          ],
        ),
      ),
    );
  }
}

Main Properties

tabs

List of Tab widgets to be shown

Type: List<Widget>

Required: Yes

controller

Controls the selected tab and the animation

Type: TabController

Required: No (created automatically)

isScrollable

Allows horizontal scrolling

Type: bool

Default: false

indicatorColor

Color of the active tab indicator

Type: Color

Default: Theme accentColor

labelColor

Color of the active tab's text

Type: Color

Default: Theme accentColor

unselectedLabelColor

Color of inactive tabs' text

Type: Color

Default: Theme unselectedWidgetColor

Widget Tab

text

Tab text

text: 'Home'

icon

Tab icon

icon: Icon(Icons.home)

child

Custom widget for the tab

child: Text('Home')

height

Custom tab height

height: 60

Tab Examples:

// Tab con icono y textoTab(icon: Icon(Icons.home), text: 'Home')

// Tab solo con textoTab(text: 'Settings')

// Tab solo con iconoTab(icon: Icon(Icons.star))

// Tab personalizadoTab(
  child: Row(
    children: [
      Icon(Icons.notifications),
      SizedBox(width: 4),
      Text('Notificaciones'),
    ],
  ),
)

Visual Examples

1. TabBar Classic

Chats
Estados
Llamadas

Chat List

  • Ana - Hola!
  • Carlos - ¿Cómo estás?
  • Maria - Reunión mañana
DefaultTabController(
  length: 3,
  child: Scaffold(
    appBar: AppBar(
      title: Text('Mi App'),
      bottom: TabBar(
        tabs: [
          Tab(text: 'Chats'),
          Tab(text: 'Estados'),
          Tab(text: 'Llamadas'),
        ],
      ),
    ),
    body: TabBarView(
      children: [
        ChatsScreen(),
        StatusScreen(),
        CallsScreen(),
      ],
    ),
  ),
)

2. TabBar with Icons

Música
Podcasts
Radio

Your Music Library

Playing: Current Song

TabBar(
  tabs: [
    Tab(icon: Icon(Icons.music_note), text: 'Música'),
    Tab(icon: Icon(Icons.podcasts), text: 'Podcasts'),
    Tab(icon: Icon(Icons.radio), text: 'Radio'),
  ],
)

3. TabBar Custom

Hoy
Semana
Mes
Year

Today's Statistics

Sales: \$1,250

Visits: 342

TabBar(
  indicator: BoxDecoration(
    borderRadius: BorderRadius.circular(25),
    color: Colors.deepPurple,
  ),
  labelColor: Colors.white,
  unselectedLabelColor: Colors.deepPurple,
  tabs: [
    Tab(text: 'Hoy'),
    Tab(text: 'Semana'),
    Tab(text: 'Mes'),
    Tab(text: 'Year'),
  ],
)

TabController Manual

For more advanced control, you can use TabController manually with StatefulWidget.

TabController with StatefulWidget

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

  @override
  State<TabControllerExample> createState() => _TabControllerExampleState();
}

class _TabControllerExampleState extends State<TabControllerExample> 
    with SingleTickerProviderStateMixin {
  
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('TabController Manual'),
        bottom: TabBar(
          controller: _tabController,
          tabs: const [
            Tab(text: 'News'),
            Tab(text: 'Sports'),
            Tab(text: 'Technology'),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: const [
          NewsScreen(),
          SportsScreen(),
          TechnologyScreen(),
        ],
      ),
    );
  }
}

Customizer for TabBar

3 tabs
Contenido de Pestaña

This is the content of the selected tab...

// El código se generará aquí

TabBarView

The TabBarView widget shows the content corresponding to each tab.

Implementation of TabBarView

TabBarView(
  children: [
    // Contenido para la primera pestaña    ListView.builder(
      itemCount: 20,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text('Element \$index'),
        );
      },
    ),
    
    // Contenido para la segunda pestaña    GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
      itemCount: 10,
      itemBuilder: (context, index) {
        return Card(
          child: Center(child: Text('Card \$index')),
        );
      },
    ),
    
    // Contenido para la tercera pestaña    Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(Icons.person, size: 64),
          Text('Perfil de Usuario'),
        ],
      ),
    ),
  ],
)

Best Practices

✅ What you SHOULD do

  • Use between 2 and 5 tabs maximum
  • Keep labels short and descriptive
  • Use recognizable icons when possible
  • Consider using manual TabController for complex cases
  • Use TabBarView for related content

❌ What you should NOT do

  • Don't use more than 5-6 tabs (better to use scrollable)
  • Avoid very long labels
  • Don't mix different navigation patterns
  • Don't forget to dispose() the manual TabController
  • Don't use tabs for unrelated functionality

Pro Tip

To improve performance with many tabs, consider using AutomaticKeepAliveClientMixin to preserve each tab's state and avoid unnecessary rebuilds.

Exercises to Practice

Exercise 1: News App

Create a news app with tabs for different categories.

Suggested tabs: Latest, Sports, Technology, Entertainment

Exercise 2: Weather App

Implement a weather app with tabs for different cities.

Suggested tabs: Current City, Favorites, Extended Forecast

Exercise 3: Tasks App

Create a tasks app with tabs for different statuses.

Suggested tabs: All, Pending, Completed, Archived

Common Troubleshooting

❌ Tabs don't change when swiping

Solution: Make sure to use the same TabController in TabBar and TabBarView

controller: _tabController // en ambos widgets

❌ Error: 'TabController vsync was null'

Solution: Implement SingleTickerProviderStateMixin in your State

with SingleTickerProviderStateMixin

❌ The content doesn't update

Solution: Use AutomaticKeepAliveClientMixin to preserve the state

with AutomaticKeepAliveClientMixin

Additional Resources

📚 Official Documentation

See the complete TabBar documentation on flutter.dev

View Documentation

💡 Advanced Examples

Discover creative implementations of TabBar

Explore Examples