Understanding SwiftUI's TabView
Apple's documentation for the iOS 26 Tab API is text-heavy with few visuals. I'm a beginner iOS developer, so I built several examples and recorded them to understand how TabView actually behaves.
API Redesign
iOS 26 replaced .tabItem modifiers with a dedicated Tab component. The old API required wrapping labels in closures. The new syntax consolidates everything:
Before:
Text("Home").tabItem { Label("Home", systemImage: "house") }
After:
Tab("Home", systemImage: "house") { Text("Home") }
The result is less nesting and clearer intent.
Example Setup
For visual consistency across examples, I extracted styling into TabViewHelpers.swift:
// TabViewHelpers.swift - shared across all examples
extension View {
var rainbowGradient: some View {
LinearGradient(
colors: [.red, .orange, .yellow, .green, .blue, .purple],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
.ignoresSafeArea()
}
func tabContent(_ text: String) -> some View {
Text(text)
.font(.system(size: 40, weight: .bold))
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
.padding(.bottom, 100)
.background(rainbowGradient)
}
}
This keeps examples focused on TabView structure. The rainbow gradient makes liquid glass effects more visible in videos.
Basic Tab Example
A standard TabView with three tabs:
TabView {
Tab("Home", systemImage: "house") {
tabContent("Home")
}
Tab("Automation", systemImage: "checkmark.circle") {
tabContent("Automation")
}
Tab("Discover", systemImage: "star") {
tabContent("Discover")
}
}
Each Tab needs a label, icon, and content. TabView handles state persistence, animations, and accessibility automatically.
iOS 26 introduced "liquid-glass"—a frosted tab bar that adapts to content behind it. The effect is automatic. As you switch tabs, the backdrop blur adjusts dynamically. No configuration is needed.
Notice how the gradient shifts through the frosted tab bar as you navigate:
Search Role
Tab(role: .search) is special. The search role automatically provides the magnifying glass icon and semantic context to iOS:
TabView {
Tab("Issues", systemImage: "newspaper") {
tabContent("Issues")
}
Tab("About", systemImage: "info.circle") {
tabContent("About")
}
Tab(role: .search) {
tabContent("Search")
}
}
The magnifying glass is locked in—no customization. This ensures consistent search recognition across iOS. Apps like App Store and Music follow this pattern.
Warning
Only one Tab(role: .search) is allowed per TabView. Adding a second one compiles but produces undefined behavior at runtime.
Badges
.badge() adds notification bubbles to tabs:
struct BadgedTabView: View {
@State private var messageCount = 3
@State private var notificationCount = 7
var body: some View {
VStack {
// Control buttons
HStack {
Button("Add Message") {
messageCount += 1
}
Button("Clear Notifications") {
notificationCount = 0
}
}
.padding()
TabView {
Tab("Messages", systemImage: "message") {
tabContent("Messages (\(messageCount))")
}
.badge(messageCount)
Tab("Notifications", systemImage: "bell") {
tabContent("Notifications (\(notificationCount))")
}
.badge(notificationCount)
Tab("Profile", systemImage: "person") {
tabContent("Profile")
}
}
}
}
}
Badges hide at 0, and iOS handles positioning and styling. Messages, Mail, and Phone use this pattern for unread counts.
What You Can't Customize
Apple enforces conventions to maintain iOS consistency.
Search Is Locked Down
Tab(role: .search) cannot be repurposed. You can't replace it with an "Add" button. The icon is fixed, only one search role is allowed per TabView, and iOS determines its position.
Apple's reasoning: search should be instantly recognizable. The magnifying glass is universal.
Other Restrictions
Important
iOS 26 forces tab bars near the top on iPad, and liquid glass styling cannot be disabled. Test on both iPhone and iPad to confirm your layout adapts.
More than 5 tabs: iOS adds a "More" tab automatically. You can't customize or remove it. The system decides which tabs get hidden.
iPad layout: iOS 26 forces tab bars near the top. The old bottom position is gone. Sidebar toggle is system-controlled.
Tab bar appearance: Limited color, blur, and spacing customization. Liquid glass is the default—you can't disable it or swap in custom materials.
Tab ordering: Users can reorder in the "More" menu (requires customizationID). Sidebar doesn't always sync with TabView order.
Most apps stay within these constraints. The defaults cover common cases and maintain iOS consistency.
Design Guidelines
Apple's recommendations:
Structure
- 3-5 tabs on iPhone
- Clear SF Symbol icons
- Concise titles (1-2 words)
- Sparse badging (only for things that need attention)
Hierarchy
- Primary actions in main tabs
- Secondary content in TabSections (iOS 26+)
- Search always uses
Tab(role: .search)
Responsive
- Size class adaptation for different screens
.sidebarAdaptablefor iPad- 44pt minimum touch targets
Related posts:
- SwiftUI's Toolbar placement API - Learn how to customize toolbar buttons and bottom bars in SwiftUI
- SwiftUI Liquid Glass and Accessibility - Make your tab views accessible with Reduce Motion and VoiceOver support