Skip to content

UITab for iOS 18+

Introduced in iOS 18, UITab is a modern UIKit API for defining tabs in a UITabBarController, offering enhanced customization and flexibility for navigation across iOS, iPadOS, and macOS Catalyst apps. It replaces or complements traditional UITabBarItem with programmatic control over tab presentation, including support for badges, nested tab groups, and specialized tabs like UISearchTab for search functionality.

Overview

UITab encapsulates a view controller, title, image, and optional badge, managed by a UITabBarController via its tabs property. It supports adaptive layouts (e.g., bottom tab bar on iPhone, sidebar on iPad) and integrates with new APIs like UISearchTab for streamlined search experiences. UITab is designed for iOS 18+ and enhances tab-based navigation with modern UIKit features.

Key Features:

  • Programmatic tab creation with customizable titles, images, and badges.
  • Support for UISearchTab for dedicated search tabs.
  • Adaptive presentation for iPhone, iPad, and Mac.
  • Integration with UITabGroup for hierarchical tab structures.

Basic Setup

Create a UITabBarController and assign UITab objects to its tabs property.

Example: Basic UITab Setup:

swift
import UIKit

class TabBarController: UITabBarController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let homeVC = UIViewController()
        let homeTab = UITab(viewController: homeVC, title: "Home", image: UIImage(systemName: "house"))
        
        let profileVC = UIViewController()
        let profileTab = UITab(viewController: profileVC, title: "Profile", image: UIImage(systemName: "person"))
        
        tabs = [homeTab, profileTab]
        
        // Customize tab bar appearance
        tabBar.tintColor = .systemBlue
        tabBar.backgroundColor = .systemBackground
    }
}

This creates a tab bar with "Home" and "Profile" tabs.

Giving Tabs Badges

Badges on UITab objects display notifications or counts (e.g., unread messages) using the badgeValue property. Customize badge appearance via UITabBarAppearance.

Example: Adding Badges:

swift
extension TabBarController {
    func updateBadge(forTabAt index: Int, count: Int) {
        guard index < tabs.count else { return }
        let tab = tabs[index]
        tab.badgeValue = count > 0 ? "\(count)" : nil
        
        // Customize badge appearance
        if #available(iOS 18.0, *) {
            let appearance = UITabBarAppearance()
            appearance.stackedLayoutAppearance.normal.badgeBackgroundColor = .systemRed
            appearance.stackedLayoutAppearance.normal.badgeTextAttributes = [.foregroundColor: UIColor.white]
            tabBar.standardAppearance = appearance
        }
    }
}

Usage:

swift
class HomeViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        
        // Simulate notifications
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            if let tabBarController = self.tabBarController as? TabBarController {
                tabBarController.updateBadge(forTabAt: 0, count: 3)
            }
        }
    }
}

This adds a red badge with "3" to the "Home" tab after a delay.

Creating a Search Tab using UISearchTab

UISearchTab is a specialized UITab subclass introduced in iOS 18 for creating a dedicated search tab with an embedded UISearchController. It automatically configures a search bar and supports search results presentation, optimized for tab-based navigation.

Example: Search Tab with UISearchTab:

swift
extension TabBarController {
    func setupSearchTab() {
        if #available(iOS 18.0, *) {
            // Create a view controller for search results
            let searchResultsVC = UIViewController()
            searchResultsVC.view.backgroundColor = .systemBackground
            
            // Configure search controller
            let searchController = UISearchController(searchResultsController: searchResultsVC)
            searchController.searchBar.placeholder = "Search Items"
            searchController.searchResultsUpdater = self
            
            // Create UISearchTab
            let searchTab = UISearchTab(title: "Search",
                                        image: UIImage(systemName: "magnifyingglass"),
                                        searchController: searchController)
            
            // Embed in navigation controller for large titles
            let navController = UINavigationController(rootViewController: searchTab.viewController)
            navController.navigationBar.prefersLargeTitles = true
            
            // Add to tabs
            tabs.append(searchTab)
        }
    }
}

extension TabBarController: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        guard let query = searchController.searchBar.text, !query.isEmpty else { return }
        // Update search results view controller
        if let resultsVC = searchController.searchResultsController {
            let label = UILabel()
            label.text = "Searching for: \(query)"
            label.frame = resultsVC.view.bounds
            label.textAlignment = .center
            resultsVC.view.addSubview(label)
        }
    }
}

Usage:

swift
class TabBarController: UITabBarController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Setup other tabs...
        setupSearchTab()
    }
}

This creates a "Search" tab using UISearchTab, embedding a UISearchController with a results view controller that displays the search query.

Best Practices

  • Use UITab for iOS 18+: Leverage UITab and UISearchTab for modern tab navigation in new projects.
  • Optimize for iPadOS: Test adaptive layouts (bottom tab bar on iPhone, sidebar on iPad) with UITab.
  • Accessibility: Set accessibilityLabel on UITab for VoiceOver (e.g., searchTab.accessibilityLabel = "Search Tab").
  • Badge Updates: Clear badges (badgeValue = nil) when notifications are resolved.
  • Search Behavior: Implement UISearchResultsUpdating to handle real-time search queries in UISearchTab.
  • Appearance Consistency: Use UITabBarAppearance to ensure badge and tab styles align with app design.

Troubleshooting

  • UISearchTab Unavailable: Ensure app targets iOS 18+ and use #available(iOS 18.0, *) checks.
  • Badge Not Visible: Verify badgeValue is set and UITabBarAppearance is configured.
  • Search Bar Not Responding: Confirm searchResultsUpdater is set and handles queries correctly.
  • Sidebar Issues on iPad: Use traitOverrides to force tab bar style if sidebar is undesired (e.g., traitOverrides.horizontalSizeClass = .compact).
  • Tab Not Rendering: Check tabs array assignment in viewDidLoad and ensure view controllers are valid.
  • Performance: Minimize heavy initialization in UISearchTab to avoid delays.

Additional Notes

  • UISearchTab and UITab are exclusive to iOS 18+ and optimized for iPadOS 18 sidebar navigation and macOS Catalyst.
  • For complex search logic, integrate UISearchTab with a data source (e.g., Core Data, network API).
  • Refer to WWDC24 session “Elevate your tab and sidebar experience in iPadOS” for advanced UITab features, such as UITabGroup.
  • Test with accessibility tools like VoiceOver to ensure UISearchTab is user-friendly.

Released under the MIT License.