Skip to content
Bugwise
Menu
UI Components

Tabs

A row of labels that switches between sibling sections of one screen. Learn the Android, iOS and web variants, how swiping, badges, deep links and Back should behave, and the state bugs testers find every sprint.

35 min Navigation iOS · Android · Web Also called: Tab bar (top), Tab strip, Navigation tabs

Open your orders in a shopping app: Active · Delivered · Returns. Tap Delivered, scroll down to last month’s parcel, peek at Returns, come back… and you’re at the top of the list again. Annoying? It’s also a bug, and one of the most common ones in apps with tabs.

Tabs look like nothing more than three words and a line. But they decide what the user sees, they must remember where the user was, and they have to agree with swipes, links, badges, the Back button and the keyboard. Let’s learn them properly.

What are tabs?

Tabs are a row of labels where each label shows a different section of the same screen. Exactly one tab is selected at a time, and the selected tab is marked by an active indicator (usually a line under it). The sections are siblings: equally important, at the same level, and the user can jump between them in any order.

You’ll usually see tabs used to:

  • Split a screen into sections: Overview / Specs / Reviews on a product page.
  • Group the same kind of items by status: Active / Delivered / Returns in orders, Upcoming / Past in a travel app.
  • Browse categories: Popular / Pizza / Sushi / Burgers… on a restaurant menu (often scrollable).
  • Switch between the main areas of an app: the tab bar at the bottom of an iPhone app (Home, Search, Orders, Account).

Anatomy

Material 3 primary tabs with icons

  1. 1

    Tab bar (container)

    Holds all tabs in one row, usually right under the top app bar.

  2. 2

    Tab

    One destination. The whole area is tappable, at least 48 dp tall on Android.

  3. 3

    Icon (optional)

    Supports the label. Icon-only tabs still need an accessible name.

  4. 4

    Label

    One or two words naming the section. Must survive long translations.

  5. 5

    Active indicator

    The line under the selected tab. It must always match the content shown.

  6. 6

    Badge

    A dot or count for new items in that tab. Must update when the count changes.

  7. 7

    Content panel

    The section the selected tab shows. Each panel keeps its own scroll and state.

How it differs from similar components

Tabs, segmented controls and bottom navigation all show “pick one of a few”. The difference is what changes when you pick. Using the wrong one is a valid design finding.

ComponentWhereWhat it switchesTypical use
Tabs (top)Under the app barSibling sections of one screenOverview / Specs / Reviews
Segmented controlSegmented controlA row of connected buttons where exactly one option is selected at a time.Open in glossary →Inside the contentViews or filters of the same dataList / Map, Day / Week / Month
Bottom navigation / iOS tab barBottom of the screenThe app’s main areas, each with its own historyHome / Search / Orders / Account
Stepper / wizardTop or inlineSteps that must happen in orderAddress → Delivery → Payment

Designs & variants

Each platform styles tabs differently, and each variant has its own weak spots.

Every demo works. Tap the tabs, swipe the Android product page sideways, scroll a list and switch away and back, and try the web one with your keyboard.

Trail runner 2

Trail runner 2, overview

Primary tabs

Android

Material 3 primary tabs sit right under the top app bar and switch between the main sections of one screen. The content can be swiped sideways, and the indicator follows.

TapSwipe contentBadgeIcon + label

Spaghetti carbonara

25 min · 4 servings

  • •400 g spaghetti
  • •2 eggs + 2 yolks
  • •150 g guanciale
  • •60 g pecorino
  • •Black pepper

Secondary tabs

Android

Secondary tabs split one area of content further down the page. The indicator spans the whole tab and the labels stay neutral in color.

Inside a sectionFull-width indicator
Pizza Roma · Menu
  • Popular item 1€7.50
  • Popular item 2€9.00
  • Popular item 3€10.50
  • Popular item 4€12.00
  • Popular item 5€13.50

Scrollable tabs

Android / web

When there are too many tabs for the width, the row scrolls sideways. The selected tab should slide into view, and a cut-off tab at the edge hints that there is more.

Many tabsSelected tab scrolls into view

Home

  • Home row 1
  • Home row 2
  • Home row 3
  • Home row 4
  • Home row 5
  • Home row 6
  • Home row 7
  • Home row 8
  • Home row 9
  • Home row 10
  • Home row 11
  • Home row 12
  • Home row 13
  • Home row 14

Tab bar (bottom)

iOS

On iPhone, the main app sections live in a bottom tab bar. Each tab keeps its own scroll position and navigation. Tapping the active tab again scrolls to the top.

Keeps state per tabBadgeTap again = top

Speckled mug

€24.00

Hand-thrown stoneware mug, 350 ml. Dishwasher and microwave safe.

Try it: Tab to the tabs, then ← → Home End

Tabs on the web

Web

An ARIA tablist: role tab and tabpanel, aria-selected on the active tab, one Tab stop for the whole row, and arrow keys to move between tabs (automatic activation).

Arrow keysHome / Endrole="tab"

Fixed or scrollable?

  • Fixed tabs share the width equally. They work for 2–4 short labels and let users see all options at once. The risk: long labels and translations get cut off.
  • Scrollable tabs keep each tab at its natural width and let the row scroll sideways. They suit many or long labels. The risks: users don’t notice there’s more, and the selected tab can end up hidden off-screen.

When to use it

Tabs are a good choice when:

  • The content splits into 2–6 sibling sections that the user may visit in any order.
  • Each section is substantial (a list, a page of details), not just a different filter of the same list.
  • Labels are short and clear (one or two words) and still fit when translated.
  • Users switch between the sections often, and want to see at a glance what exists.

Good and bad uses

Sibling sections

Three parts of one product page. Any order makes sense.

Steps that must happen in order

Users can jump to Payment before entering an address. A checkout needs a stepper with validation between steps.

Short labels, or scrollable for many

The cut-off tab at the edge hints that the row scrolls.

Too many fixed tabs

In German every label is truncated. Nobody can guess what “Techn…” means.

How good tabs behave

Most tab bugs aren’t about colors. They’re about staying in sync and remembering things. These are the rules to test against.

The indicator always tells the truth

Whatever changes the content (a tap, a swipe, a deep linkDeep linkA link that opens a specific screen inside an app instead of just its home screen.Open in glossary →, a push notification, the Back button, a rotation), the selected tab, its indicator and the content below must agree. On Android, top tabs usually let you swipe the content sideways to reach the next tab; the indicator should follow your finger and land on the new tab. A swipe that changes the page but leaves the indicator behind is a classic bug.

Each tab keeps its own state

Scroll Delivered halfway down, switch to Returns, come back: you should be exactly where you were. The same goes for filters, expanded rows, text typed in a search field and the screen you opened inside a tab. This is state persistenceState persistenceWhether the app remembers what the user did after navigating away, rotating, or restarting.Open in glossary →. Test it when switching tabs, after opening a detail screen and coming back, after rotating the device, and after the app returns from the background.

Badges stay current

A badge (Orders 2) is a promise: “there are two things waiting here”. When the number changes (an order is delivered, a message is read) the badge must update immediately, and disappear at zero. Test it while the app is open, after a push notificationPush notificationA message an app sends to the device that appears even when the app is closed.Open in glossary →, and after coming back from the background.

Emails, push notifications and web links often point to a specific tab: shop://orders/returns, or shop.example.com/product/42?tab=reviews on the web. The link must open that tab, with the indicator on it, both when the app is closed and when it’s already open on another tab. On the web, the selected tab often lives in the URL (a query parameterQuery parameterData in a URL after the ?, like ?q=mug&sort=price, often used to keep search and filter state.Open in glossary → or #reviews), so refreshing the page or sharing the link keeps the tab.

Back behaves the same way every time

Teams decide this, and the decision must be consistent:

  • On Android, switching top tabs usually doesn’t create history: Back leaves the screen rather than visiting the previous tab.
  • With bottom navigation, Back usually returns to the start tab first, then exits the app.
  • Back from a detail screen opened inside a tab returns to that tab, exactly where the user was, whether they used the app’s back arrow, the system Back button or the Back gesture.
  • On the web, decide whether each tab click adds a browser history entry. Either way, browser Back must never land on a broken or empty tab.

Labels fit in every language

German and Finnish labels are often 30–50% longer than English. Fixed tabs then truncateTruncationText that gets cut off because it doesn't fit its space.Open in glossary → or clip labels. Good apps switch to scrollable tabs, shorten the copy, or wrap to two lines. Check with every supported language, a narrow phone, and the largest text size (Dynamic TypeDynamic TypeThe phone setting that lets users make text bigger or smaller across apps.Open in glossary → on iOS, Font size on Android).

Common bugs

#BugWhat you seeTypical severity
1Indicator out of syncAfter a swipe or deep link, the line is on Active but the content is DeliveredHigh
2Scroll or state resetEvery tab switch jumps back to the top; filters and typed text are lostMedium
3Deep link opens the wrong tabThe “Track your return” email opens Active instead of ReturnsMedium–High
4Truncated labels“Rücksendun” or “Techn…” in other languages or with large textMedium
5Stale badgeOrders 2 after both orders were delivered, or a badge that never clearsMedium
6Inconsistent BackThe arrow returns to the right tab, System Back to the first oneMedium
7No keyboard support (web)Arrow keys do nothing, every tab is a Tab stop, focus is invisibleMedium–High
8Screen reader silenceVoiceOver / TalkBack reads “button” with no “tab”, “selected” or “2 of 3”High (for affected users)
9Double loadingTapping the selected tab, or swiping back and forth, refetches everythingLow–Medium
10Selected tab off-screenIn scrollable tabs, the selected tab is hidden past the edgeLow–Medium

Stress-test it

This is a correct web tablist. Change the settings and use only your keyboard: Tab into the row, then ← → Home End. Try Deutsch + Fixed + Phone and compare Automatic with Manual activation.

Activation
Language
Layout
Width

Aero 14 laptop

€1,199

Lightweight 14" laptop, 1.2 kg, 18 h battery.

Screen reader would say

Tab into the tab row to hear it…

Key log

  • Click a tab, then use ← → Home End.

Things to notice: in Deutsch + Fixed + Phone the labels are cut off. Scrollable fixes it, but the last tab hides off-screen. In Manual mode, arrows only move focus until you press Enter or Space.

Find the bug

This Android shopping app has an orders screen with three tabs and six bugs. Explore it like a tester:

  • Tap the tabs, then swipe the list sideways (drag with the mouse or your finger).
  • Scroll Delivered down, switch tabs and come back.
  • Open an order and leave it in both ways: the back arrow and System Back.
  • Use the device panel: deliver an order, open the links, switch to Deutsch.

🐞 Bug hunt: My orders

This demo has 6 hidden bugs. Explore it like a tester, then check your findings.

Found0/6
9:41

My orders

Device

Open a link (e.g. from an email)

Event log

  • Pushes, links and Back presses appear here…
  1. 1

    Hint: Swipe the list sideways and look at the tab row.

  2. 2

    Hint: Scroll Delivered down, tap Returns, then tap Delivered again.

  3. 3

    Hint: Use the shop://orders/returns link in the device panel.

  4. 4

    Hint: Switch the device to Deutsch.

  5. 5

    Hint: Tap “Simulate: next order delivered” twice.

  6. 6

    Hint: Open an order from Delivered, then go back with System Back. Compare with the arrow.

How to test it

Checklist

Tabs test checklist

0 of 14 checked

Example test cases

TC-TAB-001Default tab on first load

Preconditions

  • User has 2 active and 14 delivered orders

Steps

  1. Open the app
  2. Go to My orders

Expected result

"Active" is selected, the indicator is under it and the 2 active orders are listed.

TC-TAB-002Swipe between tabs keeps the indicator in sync

Steps

  1. Open My orders on "Active"
  2. Swipe the list from right to left
  3. Swipe again
  4. Swipe back from left to right

Expected result

After each swipe the content, the indicator and the screen reader's selected tab all match: Delivered, Returns, Delivered.

TC-TAB-003Scroll position is kept per tab

Steps

  1. Open "Delivered" and scroll to the 10th order
  2. Tap "Returns"
  3. Tap "Delivered"

Expected result

The Delivered list is still scrolled to the 10th order. Nothing reloads.

TC-TAB-004Deep link opens the Returns tab

Preconditions

  • App is open on the Home screen

Steps

  1. Run: adb shell am start -a android.intent.action.VIEW -d "shop://orders/returns"
  2. Repeat with the app fully closed

Expected result

In both cases My orders opens with "Returns" selected and its list visible.

TC-TAB-005Back from an order detail returns to the same tab

Steps

  1. Open "Delivered", scroll down and open an order
  2. Press System Back
  3. Repeat using the app bar back arrow

Expected result

Both times the user is back on "Delivered" at the same scroll position.

TC-TAB-006Badge updates when an order is delivered

Preconditions

  • 2 active orders, badge shows 2

Steps

  1. Keep My orders open
  2. Mark one order as delivered on the backend (or receive the delivery push)
  3. Mark the second one as delivered

Expected result

The badge changes to 1, then disappears. The orders move to "Delivered".

TC-TAB-007Long labels in German

Preconditions

  • Device language: Deutsch
  • Smallest supported phone

Steps

  1. Open My orders
  2. Increase the font size to the maximum and reopen

Expected result

All labels ("Aktiv", "Zugestellt", "Rücksendungen") are fully readable, or the tab row scrolls. No label is clipped mid-word.

TC-TAB-008Keyboard navigation in a web tablist

Steps

  1. Press Tab until focus reaches the tab row
  2. Press → twice, then Home, then End
  3. Press Tab

Expected result

Focus and selection move Overview → Specs → Reviews → Overview → Q&A with a visible focus ring. The next Tab moves focus into the panel, not to the next tab.

Tip: click a test case to expand it.

Tools

  • Deep links on Android: adb shell am start -a android.intent.action.VIEW -d "shop://orders/returns" (see ADB basics).
  • Deep links on the iOS Simulator: xcrun simctl openurl booted "shop://orders/returns".
  • State after process death (Android): turn on Developer options › Don’t keep activities, switch tabs, leave the app and come back.
  • Web: check roles and aria-selected in the Elements and Accessibility panes of DevTools, and test the URL: refresh, Back and a shared link should all keep the tab.

Accessibility

Mobile vs web

  • The tab bar sits at the bottom and switches the app’s main areas. On iPhone, keep it to 5 tabs or fewer; extra ones go into a “More” tab.
    Dev note
    UITabBarController / SwiftUI TabView.
  • Each tab keeps its own navigation stack. Tapping the active tab again pops to its root or scrolls to the top.
  • There are no Material-style top tabs. Within a screen, iOS apps use a segmented control instead.
  • Badges are red with a white number. Test with VoiceOver, the largest Dynamic Type size, and on iPad, where tab bars can look different.
  • Material 3 primary tabs (under the top app bar) and secondary tabs (inside a content area), each fixed or scrollable. Bottom navigation (navigation bar) is a separate component for the app’s main areas.
  • Content can usually be swiped sideways between tabs. Test the swipe, the indicator, and that horizontal carousels inside a tab still work.
  • Check Back (button and gesture), rotation and process death: tabs must come back with the same selection and scroll position.
  • Test with TalkBack, maximum font size and display size, and long translations.
  • Usually built with HTML buttons and CSS, or a UI library, so quality varies. Inspect the ARIA tablist pattern in DevTools.
  • Check keyboard: one Tab stop, arrows, Home/End, a visible focus ring.
  • Check the URL: does ?tab=reviews or #reviews open the right tab? Do refresh and browser Back keep it?
  • Check responsive widths: on a 360 px screen, do tabs wrap, scroll or overflow the page?

Check your understanding

Quick quiz

0/5 answered · 0 correct

  1. 1.You swipe the Orders list to the left. The Delivered orders appear, but the line is still under "Active". What is this?

  2. 2.Which design is the best fit for tabs?

  3. 3.On iPhone, where do you usually find what Android shows as top tabs inside a screen?

  4. 4.In a web tablist, focus is on "Specs". What should the Right arrow key do?

  5. 5.Which test is MOST likely to catch a lost-state bug?

Key takeaways

  • Tabs switch between sibling sections of one screen. Use something else for steps, actions, or filters of one list.
  • iOS puts main areas in a bottom tab bar and uses segmented controls where Android uses top tabs.
  • The indicator must always match the content: after taps, swipes, deep links, Back and rotation.
  • Each tab keeps its own state: scroll position, filters, typed text and opened screens.
  • Always test swipe, deep links, badges, Back, long translations, the keyboard (web) and the screen reader.

Finished this page?Nice work, this page is complete!

Mark it as done to track your progress. It's saved in this browser, no account needed.

Its review cards are now in Bites ⚡
Esc

Type to search the whole site.