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.
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
Tab bar (container)
Holds all tabs in one row, usually right under the top app bar.
- 2
Tab
One destination. The whole area is tappable, at least 48 dp tall on Android.
- 3
Icon (optional)
Supports the label. Icon-only tabs still need an accessible name.
- 4
Label
One or two words naming the section. Must survive long translations.
- 5
Active indicator
The line under the selected tab. It must always match the content shown.
- 6
Badge
A dot or count for new items in that tab. Must update when the count changes.
- 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.
| Component | Where | What it switches | Typical use |
|---|---|---|---|
| Tabs (top) | Under the app bar | Sibling sections of one screen | Overview / Specs / Reviews |
| Segmented controlSegmented controlA row of connected buttons where exactly one option is selected at a time.Open in glossary → | Inside the content | Views or filters of the same data | List / Map, Day / Week / Month |
| Bottom navigation / iOS tab bar | Bottom of the screen | The app’s main areas, each with its own history | Home / Search / Orders / Account |
| Stepper / wizard | Top or inline | Steps that must happen in order | Address → 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
AndroidMaterial 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.
Spaghetti carbonara
25 min · 4 servings
- •400 g spaghetti
- •2 eggs + 2 yolks
- •150 g guanciale
- •60 g pecorino
- •Black pepper
- 1.Boil the pasta
- 2.Crisp the guanciale
- 3.Whisk eggs and cheese
- 4.Toss off the heat
- 5.Serve at once
- •Energy · 640 kcal
- •Protein · 28 g
- •Carbs · 74 g
- •Fat · 24 g
- •Salt · 2.1 g
Secondary tabs
AndroidSecondary tabs split one area of content further down the page. The indicator spans the whole tab and the labels stay neutral in color.
- 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
- Pizza item 1€7.50
- Pizza item 2€9.00
- Pizza item 3€10.50
- Pizza item 4€12.00
- Pizza item 5€13.50
- Sushi item 1€7.50
- Sushi item 2€9.00
- Sushi item 3€10.50
- Sushi item 4€12.00
- Sushi item 5€13.50
- Burgers item 1€7.50
- Burgers item 2€9.00
- Burgers item 3€10.50
- Burgers item 4€12.00
- Burgers item 5€13.50
- Vegan item 1€7.50
- Vegan item 2€9.00
- Vegan item 3€10.50
- Vegan item 4€12.00
- Vegan item 5€13.50
- Desserts item 1€7.50
- Desserts item 2€9.00
- Desserts item 3€10.50
- Desserts item 4€12.00
- Desserts item 5€13.50
- Drinks item 1€7.50
- Drinks item 2€9.00
- Drinks item 3€10.50
- Drinks item 4€12.00
- Drinks item 5€13.50
- Breakfast item 1€7.50
- Breakfast item 2€9.00
- Breakfast item 3€10.50
- Breakfast item 4€12.00
- Breakfast item 5€13.50
Scrollable tabs
Android / webWhen 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.
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
Search
- Search row 1
- Search row 2
- Search row 3
- Search row 4
- Search row 5
- Search row 6
- Search row 7
- Search row 8
- Search row 9
- Search row 10
- Search row 11
- Search row 12
- Search row 13
- Search row 14
Orders
- Orders row 1
- Orders row 2
- Orders row 3
- Orders row 4
- Orders row 5
- Orders row 6
- Orders row 7
- Orders row 8
- Orders row 9
- Orders row 10
- Orders row 11
- Orders row 12
- Orders row 13
- Orders row 14
Account
- Account row 1
- Account row 2
- Account row 3
- Account row 4
- Account row 5
- Account row 6
- Account row 7
- Account row 8
- Account row 9
- Account row 10
- Account row 11
- Account row 12
- Account row 13
- Account row 14
Tab bar (bottom)
iOSOn 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.
Speckled mug
€24.00
Try it: Tab to the tabs, then ← → Home End
Tabs on the web
WebAn 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).
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.
Deep links open the right tab
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
| # | Bug | What you see | Typical severity |
|---|---|---|---|
| 1 | Indicator out of sync | After a swipe or deep link, the line is on Active but the content is Delivered | High |
| 2 | Scroll or state reset | Every tab switch jumps back to the top; filters and typed text are lost | Medium |
| 3 | Deep link opens the wrong tab | The “Track your return” email opens Active instead of Returns | Medium–High |
| 4 | Truncated labels | “Rücksendun” or “Techn…” in other languages or with large text | Medium |
| 5 | Stale badge | Orders 2 after both orders were delivered, or a badge that never clears | Medium |
| 6 | Inconsistent Back | The arrow returns to the right tab, System Back to the first one | Medium |
| 7 | No keyboard support (web) | Arrow keys do nothing, every tab is a Tab stop, focus is invisible | Medium–High |
| 8 | Screen reader silence | VoiceOver / TalkBack reads “button” with no “tab”, “selected” or “2 of 3” | High (for affected users) |
| 9 | Double loading | Tapping the selected tab, or swiping back and forth, refetches everything | Low–Medium |
| 10 | Selected tab off-screen | In scrollable tabs, the selected tab is hidden past the edge | Low–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.
Aero 14 laptop
€1,199
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.
My orders
Device
Open a link (e.g. from an email)
Event log
- Pushes, links and Back presses appear here…
- 1
Hint: Swipe the list sideways and look at the tab row.
- 2
Hint: Scroll Delivered down, tap Returns, then tap Delivered again.
- 3
Hint: Use the shop://orders/returns link in the device panel.
- 4
Hint: Switch the device to Deutsch.
- 5
Hint: Tap “Simulate: next order delivered” twice.
- 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 loadpositivehigh
Preconditions
- User has 2 active and 14 delivered orders
Steps
- Open the app
- 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 syncpositivehigh
Steps
- Open My orders on "Active"
- Swipe the list from right to left
- Swipe again
- 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 tabpositivemedium
Steps
- Open "Delivered" and scroll to the 10th order
- Tap "Returns"
- Tap "Delivered"
Expected result
The Delivered list is still scrolled to the 10th order. Nothing reloads.
TC-TAB-004Deep link opens the Returns tabpositivehigh
Preconditions
- App is open on the Home screen
Steps
- Run: adb shell am start -a android.intent.action.VIEW -d "shop://orders/returns"
- 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 tabpositivemedium
Steps
- Open "Delivered", scroll down and open an order
- Press System Back
- 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 deliverededgemedium
Preconditions
- 2 active orders, badge shows 2
Steps
- Keep My orders open
- Mark one order as delivered on the backend (or receive the delivery push)
- 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 Germanedgemedium
Preconditions
- Device language: Deutsch
- Smallest supported phone
Steps
- Open My orders
- 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 tablistpositivemedium
Steps
- Press Tab until focus reaches the tab row
- Press → twice, then Home, then End
- 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-selectedin the Elements and Accessibility panes of DevTools, and test the URL: refresh, Back and a shared link should all keep the tab.
Accessibility
- Roles and state. Each tab must be announced as a tab, with its label, its selected state and its position (“Reviews, tab, 2 of 3”). Native iOS and Android tabs do this; custom ones often read “button”.
Dev note
On the web, userole="tablist",role="tab"witharia-selectedandaria-controls, androle="tabpanel"witharia-labelledby(this is the ARIAARIAHTML attributes that tell assistive technology what custom elements are and what state they're in.Open in glossary → tabs pattern). - Keyboard (web). keyboard navigationKeyboard navigationUsing a website with only the keyboard: Tab to move, Enter or Space to activate, Esc to close.Open in glossary → works like this: Tab enters the row on the selected tab, ← → move between tabs (wrapping at the ends), Home / End jump to the first / last, and the next Tab goes into the panel. Every tab being a separate Tab stop is a bug.
- Badges need words. A red “2” means nothing to a screen readerScreen readerSoftware that reads the screen aloud for blind and low-vision users, like VoiceOver or TalkBack.Open in glossary →. The tab should be read as “Orders, 2 new” (or similar).
- Don’t rely on color alone. The selected tab needs an indicator line or weight change, not just a slightly different text color. The indicator needs 3:1 contrast with its background, labels 4.5:1.
- Touch targetsTouch targetThe area of the screen that responds to a tap, which should be large enough for a finger.Open in glossary →: at least 44×44 pt on iOS and 48×48 dp on Android, including small icon-only tabs. On the web, WCAG 2.5.8 (AA) asks for at least 24×24 CSS px; 44×44 px (2.5.5, AAA) is the comfortable target.
- Swiping is optional. Every tab must also be reachable by a tap or a key, because some users can’t swipe.
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/ SwiftUITabView. - 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=reviewsor#reviewsopen 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.You swipe the Orders list to the left. The Delivered orders appear, but the line is still under "Active". What is this?
2.Which design is the best fit for tabs?
3.On iPhone, where do you usually find what Android shows as top tabs inside a screen?
4.In a web tablist, focus is on "Specs". What should the Right arrow key do?
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 ⚡