Skip to content

Tabs

Tabs organize content across different screens, data sets, and other interactions.

Example travel app with Explore, Flights, and Trips tabs

Contents

Design and API Documentation

Using tabs

Before you can use Material tabs, you need to add a dependency to the Material Components for Android library. For more information, go to the Getting started page.

Basic usage

Three fixed tabs with one tab selected.

A TabLayout can be added to a layout:

xml
<com.google.android.material.tabs.TabLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    ...

</com.google.android.material.tabs.TabLayout>

TabItems can then be added as children of the TabLayout and adjusted as needed:

xml
<com.google.android.material.tabs.TabLayout
    ...>

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/text_label_1"
        />

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/text_label_2"
        />

    ...

</com.google.android.material.tabs.TabLayout>

Observe changes to tab selections:

kt
tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {

    override fun onTabSelected(tab: TabLayout.Tab?) {
        // Handle tab select
    }

    override fun onTabReselected(tab: TabLayout.Tab?) {
        // Handle tab reselect
    }

    override fun onTabUnselected(tab: TabLayout.Tab?) {
        // Handle tab unselect
    }
})

API and source code:

Making tabs accessible

The Android tab components support screen reader descriptions for tabs and badges. While optional, we strongly encourage their use.

Content descriptions

Adding a content description to the entire TabLayout can be done in XML with the android:contentDescription attribute or programmatically:

kt
tabLayout.contentDescription = contentDescription

Content descriptions can also be added to individual tabs:

kt
val tab = tabLayout.getTabAt(index)
tab?.contentDescription = contentDescription

BadgeDrawable also has a number of content description setters for different badge states:

kt
val badge = tab.getOrCreateBadge()

// For badges with a number
badge.setContentDescriptionNumberless(contentDescription)
badge.setContentDescriptionQuantityStringsResource(R.string.content_description)
badge.setContentDescriptionExceedsMaxBadgeNumberStringResource(R.string.content_description)

// For badges with a text
badge.setContentDescriptionForText(contentDescription)

Using tabs with ViewPager

A TabLayout can be set up with a ViewPager in order to:

  • Dynamically create TabItems based on the number of pages, their titles, etc.
  • Synchronize the selected tab and tab indicator position with page swipes

First, your PagerAdapter (or subclass) needs to override the getPageTitle function in order to set the tab text label:

kt
class Adapter : PagerAdapter() {

    ...

    override fun getPageTitle(position: Int): CharSequence? {
        // Return tab text label for position
    }
}

After the adapter has been set on the ViewPager, synchronize the TabLayout:

kt
tabLayout.setupWithViewPager(viewPager)

Further customization of the dynamically-created TabItems (such as setting icons) needs to be done separately:

kt
val tab = tabLayout.getTabAt(index)
tab?.icon = drawable

Using tabs with ViewPager2

Setting up a TabLayout with a ViewPager2 relies on the same concepts as doing so with a ViewPager, but the implementation is different. Everything is handled by the TabLayoutMediator class:

kt
TabLayoutMediator(tabLayout, viewPager2) { tab, position ->
    when (position) {
        0 -> {
            tab.text = textLabel1
            tab.icon = drawable1
        }
        1 -> {
            tab.text = textLabel2
            tab.icon = drawable2
        }
        ...
    }
}.attach()

Adding badges to tabs

Example of 3 fixed tabs with badges: a red badge with "1", a red badge with
"88", and a red badge with "999".

Tabs support badging with the BadgeDrawable class:

kt
// Get badge from tab (or create one if none exists)
val badge = tab.getOrCreateBadge()
// Customize badge
badge.number = number
// Remove badge from tab
tab.removeBadge()

Types

There are two types of tabs: 1. Fixed tabs, 2. Scrollable tabs

Composite image: Pets with Dogs, Cats, and Birds tabs; Dog breeds with
Pitbulls, Terrier, Poodle, Labrador (partial)

Fixed tabs

Fixed tabs display all tabs on one screen, with each tab at a fixed width. The width of each tab is determined by dividing the number of tabs by the screen width. They don’t scroll to reveal more tabs; the visible tab set represents the only tabs available.

Fixed tabs example

The following example shows a row of fixed tabs.

Example of 3 fixed tabs.

In the layout:

xml
<com.google.android.material.tabs.TabLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:tabMode="fixed">

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tab_1"
        android:icon="@drawable/ic_favorite_24dp"
        />

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tab_2"
        android:icon="@drawable/ic_music_24dp"
        />

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tab_3"
        android:icon="@drawable/ic_search_24dp"
        />

</com.google.android.material.tabs.TabLayout>

Scrollable tabs

Scrollable tabs are displayed without fixed widths. They are scrollable, such that some tabs will remain off-screen until scrolled.

Scrollable tabs example

The following example shows a row of scrollable tabs.

Example of 6 scrollable tabs, with the 6th partially cut off by screensize.

In the layout:

xml
<com.google.android.material.tabs.TabLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:tabMode="scrollable"
    app:tabContentStart="56dp">

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tab_1"
        />

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tab_2"
        />

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tab_3"
        />

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tab_4"
        />

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tab_5"
        />
    ...
</com.google.android.material.tabs.TabLayout>

Anatomy and key properties

Tabs have a container and each tab item has an optional icon and text label. Tab items can be in an active or inactive state. The tab indicator is shown below the active tab item.

Tabs anatomy diagram

  1. Container
  2. Active icon (optional if there’s a label)
  3. Active text label (optional if there’s an icon)
  4. Active tab indicator
  5. Inactive icon (optional if there’s a label)
  6. Inactive text label (optional if there’s an icon)
  7. Tab item

Container attributes

ElementAttributeRelated method(s)Default value
Colorandroid:backgroundsetBackground
getBackground
?attr/colorOnSurfaceVariant
Elevationandroid:elevationsetElevation0dp
HeightN/AN/A48dp (inline text) or 72dp (non-inline text and icon)
Tab modetabModesetTabMode
getTabMode
fixed

Tab item icon attributes

ElementAttributeRelated method(s)Default value
Iconandroid:iconsetIcon
getIcon
null
ColortabIconTintsetTabIconTint
setTabIconTintResource
getTabIconTint
colorOnSurfaceVariant and colorPrimary (activated) (see all states)

Tab item text label attributes

ElementAttributeRelated method(s)Default value
Textandroid:textsetText
getText
null
ColortabTextColorsetTabTextColors
getTabTextColors
colorOnSurfaceVariant and colorPrimary (activated) (see all states)
TypographytabTextAppearanceN/A?attr/textAppearanceTitleSmall
Active tab typographytabSelectedTextAppearanceN/ANone; will use tabTextAppearance instead
Inline labeltabInlineLabelsetInlineLabel
setInlineLabelResource
isInlineLabel
false

Note: When using tabSelectedTextAppearance, you must have matching text attributes in tabTextAppearance to avoid unintended behavior.

Tab item container attributes

ElementAttributeRelated method(s)Default value
Ripple colortabRippleColorsetTabRippleColor
setTabRippleColorResource
getTabRippleColor
colorOnSurfaceVariant at 16% opacity and colorPrimary at 16% opacity (activated) (see all states)
Unbounded rippletabUnboundedRipplesetUnboundedRipple
setUnboundedRippleResource
hasUnboundedRipple
true
GravitytabGravitysetTabGravity
getTabGravity
fill
Min widthtabMinWidthN/A72dp (scrollable) or wrap_content
Max widthtabMaxWidthN/A264dp
PaddingtabPaddingStart
tabPaddingEnd
tabPaddingTop
tabPaddingBottom
tabPadding
N/A12dp
12dp
0dp
0dp
0dp

Tab indicator attributes

ElementAttributeRelated method(s)Default value
ColortabIndicatorColorsetSelectedTabIndicatorColorcolorPrimary
DrawabletabIndicatorsetSelectedTabIndicator
getSelectedTabIndicator
m3_tabs_rounded_line_indicator
HeighttabIndicatorHeightsetSelectedTabIndicatorHeight2dp
Full widthtabIndicatorFullWidthsetTabIndicatorFullWidth
isTabIndicatorFullWidth
false
Animation modetabIndicatorAnimationModesetTabIndicatorAnimationMode
getTabIndicatorAnimationMode
elastic
GravitytabIndicatorGravitysetSelectedTabIndicatorGravity
getTabIndicatorGravity
bottom
Animation durationtabIndicatorAnimationDurationN/A250

Styles

ElementStyle
Default styleWidget.Material3.TabLayout
Style for elevateable surfacesWidget.Material3.TabLayout.OnSurface
Primary secondary color styleWidget.Material3.TabLayout.Secondary

Default style theme attribute: ?attr/tabStyle

Additional style theme attributes: ?attr/tabSecondaryStyle

See the full list of styles and attrs.

Theming tabs

Tabs support Material Theming which can customize color and typography.

Tabs theming example

API and source code:

The following example shows a row of scrollable tabs with Material Theming.

Example of 4 scrollable tabs with light pink background. The selected text is
dark pink, the unselected text is grey.

Implementing tabs theming

Use theme attributes and styles in res/values/styles.xml which applies to all tabs and affects other components:

xml
<style name="Theme.App" parent="Theme.Material3.*">
    ...
    <item name="colorPrimary">@color/shrine_pink_900</item>
    <item name="colorSurface">@color/shrine_pink_light</item>
    <item name="colorOnSurface">@color/shrine_pink_900</item>
    <item name="textAppearanceLabelLarge">@style/TextAppearance.App.LabelLarge</item>
</style>

<style name="TextAppearance.App.LabelLarge" parent="TextAppearance.Material3.LabelLarge">
    <item name="fontFamily">@font/rubik</item>
    <item name="android:fontFamily">@font/rubik</item>
</style>

Use default style theme attributes, styles and theme overlays, which apply to all tabs but do not affect other components:

xml
<style name="Theme.App" parent="Theme.Material3.*">
    ...
    <item name="tabStyle">@style/Widget.App.LabelLarge</item>
</style>

<style name="Widget.App.TabLayout" parent="Widget.Material3.TabLayout">
    <item name="materialThemeOverlay">@style/ThemeOverlay.App.TabLayout</item>
    <item name="tabTextAppearance">@style/TextAppearance.App.LabelLarge</item>
</style>

<style name="ThemeOverlay.App.TabLayout" parent="">
    <item name="colorPrimary">@color/shrine_pink_900</item>
    <item name="colorSurface">@color/shrine_pink_light</item>
    <item name="colorOnSurface">@color/shrine_pink_900</item>
</style>

Use the style in the layout, which affects only these tabs:

xml
<com.google.android.material.tabs.TabLayout
    ...
    style="@style/Widget.App.TabLayout"
    />
Tabs has loaded