How to Use Tabs Components in Jetpack Compose?

How to Use Tabs Components in Jetpack Compose (With Usage Examples)

Overview

Tabs in Jetpack Compose organize related content into groups, enabling seamless navigation. PrimaryTabRow places tabs at the top of a content pane under a top app bar for main destinations, while SecondaryTabRow separates content within a screen for additional hierarchy.

This guide demonstrates how to implement primary and secondary tabs with navigation and customization options.

When to Use Tabs

Tab Type When to Use
Primary Tabs Navigate between main app sections, like Songs, Albums, or Playlists in a music app.
Secondary Tabs Organize sub-content within a screen, such as filtering views (e.g., All, Favorites) in a settings section.
Custom Styled Tabs Apply branded styling or icons to tabs for enhanced visual hierarchy in complex UIs.

Creating Tabs Components in Jetpack Compose

Primary Tabs Example

Creates a primary tab row for navigating between main app sections, like Songs, Albums, and Playlists.


import androidx.compose.material3.PrimaryTabRow
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController

enum class Destination(val route: String, val label: String) {
    SONGS("songs", "Songs"),
    ALBUMS("albums", "Albums"),
    PLAYLISTS("playlists", "Playlists")
}

@Composable
fun PrimaryTabsExample(modifier: Modifier = Modifier) {
    val navController = rememberNavController()
    val startDestination = Destination.SONGS
    var selectedDestination by rememberSaveable { mutableIntStateOf(startDestination.ordinal) }
    Scaffold(
        modifier = modifier,
        topBar = {
            PrimaryTabRow(selectedTabIndex = selectedDestination) {
                Destination.entries.forEachIndexed { index, destination ->
                    Tab(
                        selected = selectedDestination == index,
                        onClick = {
                            navController.navigate(route = destination.route)
                            selectedDestination = index
                        },
                        text = {
                            Text(
                                text = destination.label,
                                maxLines = 2,
                                overflow = TextOverflow.Ellipsis
                            )
                        }
                    )
                }
            }
        }
    ) { contentPadding ->
        NavHost(navController = navController, startDestination = startDestination.route) {
            composable(Destination.SONGS.route) { Text("Songs Screen", modifier = Modifier.padding(contentPadding)) }
            composable(Destination.ALBUMS.route) { Text("Albums Screen", modifier = Modifier.padding(contentPadding)) }
            composable(Destination.PLAYLISTS.route) { Text("Playlists Screen", modifier = Modifier.padding(contentPadding)) }
        }
    }
}
    

Result: A horizontal row of three tabs (Songs, Albums, Playlists) at the top, with navigation to corresponding screens.

Scenario: Use for main navigation in apps, such as switching between music app sections like Songs, Albums, or Playlists.

Primary Tabs Properties

Property Description
selectedTabIndex Sets the index of the selected tab in PrimaryTabRow.
selected Highlights the current tab (e.g., selectedDestination == index).
onClick Handles tab clicks, navigating to a route and updating state.
text Displays tab label (e.g., Text(destination.label)).

Secondary Tabs Example

Creates a secondary tab row to organize sub-content, such as filtering views in a settings screen.


import androidx.compose.material3.SecondaryTabRow
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow

@Composable
fun SecondaryTabsExample(modifier: Modifier = Modifier) {
    var selectedTabIndex by remember { mutableIntStateOf(0) }
    val tabs = listOf("All", "Favorites", "Recent")
    SecondaryTabRow(
        selectedTabIndex = selectedTabIndex,
        modifier = modifier
    ) {
        tabs.forEachIndexed { index, title ->
            Tab(
                selected = selectedTabIndex == index,
                onClick = { selectedTabIndex = index },
                text = {
                    Text(
                        text = title,
                        maxLines = 2,
                        overflow = TextOverflow.Ellipsis
                    )
                }
            )
        }
    }
}
    

Result: A horizontal row of secondary tabs (All, Favorites, Recent) within a content area, updating content based on selection.

Scenario: Use to filter or organize sub-content, such as switching between All, Favorites, or Recent items in a settings or content screen.

Secondary Tabs Properties

Property Description
selectedTabIndex Sets the index of the selected tab in SecondaryTabRow.
selected Highlights the current tab (e.g., selectedTabIndex == index).
onClick Handles tab clicks, updating the selected tab state.
text Displays tab label (e.g., Text(title)).

Custom Styled Tabs Example

Creates a primary tab row with custom icons and colors for a branded navigation experience.


import androidx.compose.material3.PrimaryTabRow
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setVar
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MusicNote
import androidx.compose.material.icons.filled.Album
import androidx.compose.material.icons.filled.PlaylistPlay

@Composable
fun CustomStyledTabsExample(modifier: Modifier = Modifier) {
    var selectedTabIndex by remember { mutableIntStateOf(0) }
    val tabs = listOf(
        Pair("Songs", Icons.Filled.MusicNote),
        Pair("Albums", Icons.Filled.Album),
        Pair("Playlists", Icons.Filled.PlaylistPlay)
    )
    Scaffold(
        topBar = {
            PrimaryTabRow(
                selectedTabIndex = selectedTabIndex,
                containerColor = Color(0xFF1767d0),
                contentColor = Color.White,
                modifier = modifier
            ) {
                tabs.forEachIndexed { index, (title, icon) ->
                    Tab(
                        selected = selectedTabIndex == index,
                        onClick = { selectedTabIndex = index },
                        text = {
                            Text(
                                text = title,
                                maxLines = 2,
                                overflow = TextOverflow.Ellipsis
                            )
                        },
                        icon = {
                            Icon(
                                imageVector = icon,
                                contentDescription = title
                            )
                        }
                    )
                }
            }
        }
    ) { contentPadding ->
        // Screen content
    }
}
    

Result: A branded primary tab row with icons and blue styling, navigating between Songs, Albums, and Playlists.

Scenario: Use for visually enhanced navigation in apps, such as a music app with branded tabs featuring icons for main sections.

Custom Styled Tabs Properties

Property Description
selectedTabIndex Sets the index of the selected tab in PrimaryTabRow.
selected Highlights the current tab (e.g., selectedTabIndex == index).
onClick Handles tab clicks, updating the selected tab state.
text Displays tab label (e.g., Text(title)).
icon Displays an icon in the tab (e.g., Icon(imageVector = icon)).
containerColor Sets the tab row background color (e.g., Color(0xFF1767d0)).
contentColor Sets the tab text/icon color (e.g., Color.White).

Key Points for Implementation

  • PrimaryTabRow: Places tabs at the top for main navigation.
  • SecondaryTabRow: Organizes sub-content within a screen.
  • selected: Highlights the active tab based on state.
  • onClick: Handles navigation or state updates on tab click.
  • text/icon: Defines tab content with labels or icons.
  • enabled: Controls tab interactivity (true/false).
  • Accessibility: Ensure tabs have clear contentDescription for icons and sufficient touch targets (48dp) for screen readers.

Theming Tabs

Customize Tab appearance using MaterialTheme in Compose or apply specific styles via containerColor and contentColor in PrimaryTabRow or SecondaryTabRow.


import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.PrimaryTabRow
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextOverflow

@Composable
fun ThemedTabsExample(modifier: Modifier = Modifier) {
    var selectedTabIndex by remember { mutableIntStateOf(0) }
    val tabs = listOf("Songs", "Albums", "Playlists")
    MaterialTheme(
        colorScheme = MaterialTheme.colorScheme.copy(
            primary = Color(0xFF1767d0)
        )
    ) {
        Scaffold(
            topBar = {
                PrimaryTabRow(
                    selectedTabIndex = selectedTabIndex,
                    containerColor = MaterialTheme.colorScheme.primary,
                    contentColor = Color.White
                ) {
                    tabs.forEachIndexed { index, title ->
                        Tab(
                            selected = selectedTabIndex == index,
                            onClick = { selectedTabIndex = index },
                            text = {
                                Text(
                                    text = title,
                                    maxLines = 2,
                                    overflow = TextOverflow.Ellipsis
                                )
                            }
                        )
                    }
                }
            }
        ) { contentPadding ->
            // Screen content
        }
    }
}
    

Additional Resources

Material 3 - Tabs

FAQ

What is a Tabs component?

A component for organizing related content into navigable groups, using primary or secondary tab rows.


Which composables are used for Tabs?

Use Tab with PrimaryTabRow for main navigation or SecondaryTabRow for sub-content.


How to make Tabs accessible?

Ensure tabs have contentDescription for icons and 48dp touch targets for screen reader compatibility.


Can I customize Tabs appearance?

Yes, via containerColor, contentColor, or MaterialTheme.colorScheme.

Post a Comment

Previous Post Next Post