Exploring TabView Advancements in SwiftUI – Part 1

Posted in SwiftUI

December 6th, 2024

⏱ Reading Time: 6 mins

TabView is one of the most important container views in SwiftUI, as it allows us to present content in tabs and pages. It’s also the go-to view for creating tab-based applications. WWDC 2024 revealed significant advancements for the tab view, which all together simplify, but also empower the way we work with it and enable new appearances. These updates are available in iOS 18 and later and that’s the only downside to it, but other than that TabView is now an even more powerful view, especially for apps running on iPadOS and macOS.

This is the first of a two-parts tutorial where we’ll get to meet what’s new in TabView. However, you can always read about the old-good way on how to work with the TabView in SwiftUI and how to present content in pages using TabView if you are interested in these topics.

Meet the Tab view

The first and foremost advancement in the TabView container is the Tab view. It’s the brand new tool to use in order to create a tab item. Up until now we’ve had the tabItem view modifier for this job, but now things are getting simpler. There are various initializers available to use when creating a Tab instance, but a title, an image and the tab contents are what you’ll need to initialize it with most of the times.

To get a first taste of the Tab view inside a TabView, suppose we have been working on an app to use in a library. In this hypothetical app there are four tabs, Home, Books, Search, and Profile. Using this new view we can easily bring the tabbed content to life as shown next:

See that all we have to do is to provide a title, the name of a system image (SF Symbol) and the content in the closure of each Tab view. There is no more need to use the tabItem view modifier or perform any additional effort in order to create a tab item. Of course, tabItem is not difficult to use by any means either, but the Tab view gathers everything in one place and its syntax is in accordance to other views in SwiftUI.

Note: For simplicity, the content of each tab is a Text view, but in actual applications you replace them with real and meaningful custom views.

It’s important to underline here that each operating system displays the tab view differently. On iOS, for instance, it remains the all-time classic bottom tab bar, while on iPadOS it appears at the top of the screen, floating over the content.

Navigating among tabs programmatically

We often need to go from one tab to another without direct user interaction, but just because of another action that initiated such an event. For example, say that there is a button in the first tab that navigates users to a random book in the library instantly. To demonstrate that, let’s update the first tab accordingly:

To make programmatic navigation possible, there are three distinct easy steps to perform:

1 – Keep the selected tab to a state property

At first, we need to store the selected tab. We manage that by declaring a local state property to the view like the following:

You can represent the selected tab using any kind of values you want, even custom enums, as long as they conform to Hashable protocol. We keep things simple here with integer values: zero (0) indicates the first tab and we’ll go up to 3 for the last one.

2 – Initialize TabView passing the binding value of the selected tab

The next step is to update the initializer of the TabView and pass as argument the binding value of the state property that keeps the selected tab:

3 – Update the initialization of the Tab views

The first two steps are not new, as they are necessary even when using the old TabView APIs. The new part comes now, as we have to use a different Tab initializer that has an additional parameter named value.

As argument to this parameter we must assign a unique value that will make each tab programmatically distinguishable among all. If you have ever used the tag view modifier in the past, then consider this as its equivalent, with the only difference being that we provide the unique value in the initializer and not in a modifier.

That said, let’s update all Tab views as shown next with the value argument:

With all the above in place, we can go ahead and update the button in the first tab:

By setting the value 1 to selectedTab, the app will instantly navigate to the second tab every time the button gets tapped.

The new sidebarAdaptable style

What really caught the attention in WWDC 2024 regarding the tab view is a new style named sidebarAdaptable. This is an addition to the already existing styles, and it has a unique effect when used on iPadOS; it allows to switch between the default tab bar at the top and a sidebar.

Let’s consider again the initial example we met in this post, with the new sidebarAdaptable style applied to the TabView right after its closing curly bracket:

As said, the above behavior works on iPadOS only. Other systems handle this style differently; iOS keeps the default bottom tab bar, while macOS presents always a sidebar.

Creating tab sections

Along with the sidebarAdaptable style that allows to display tabs in a sidebar, another useful advancement came to make TabView even better. That is the capability to create sections and group tabs together in them.

To demonstrate that using the example of this post, we’ll create a section called Account that will have two tabs; the existing Profile and a new Settings tab. All other tabs will remain as they are, even though it would be perfectly fine to nest them under another section too.

We create a tab section using the TabSection container view and we append all necessary tabs into its closure. When switching from the sidebar back to tab bar, tab sections appear there too but without their inner tabs. When selecting a section in that state, the content of the last selected child tab item is shown to the screen.

Even though it looks quite tempting to have many tabs organized in multiple sections, you should mind iOS and the horizontal compact size on iPadOS. In these cases, all tabs are going to be visible without being grouped into sections, so you will end up with a cluttered tab bar having items not fitting in it.

Of course, there is a way to work around that by displaying different tab items on each occasion, but how far we can go depends on their number and existing sections. In addition to that, we can enable users to re-arrange items, drag and drop tabs and more.

All these seem to be quite interesting, but they’ll come in the second part of this post. So, stay tuned and don’t miss anything out!

Summary

This post describes the fundamental knowledge you need to have in order to work with the new tools made available for the TabView container in SwiftUI. Working with the new Tab view, changing tabs programmatically, and applying the new impressive sidebarAdaptable style seem handy and easy. It’s also really great to have tab sections. But the story does not end here, and in the second part of this tutorial we’ll dig a bit deeper, so you can provide a better user experience displaying different tab items suitable for each system, but also by providing customization options. So, stick around for the next part. Thank you for reading!

Stay Up To Date

Subscribe to my newsletter and get notifiied instantly when I post something new on SerialCoder.dev.

    We respect your privacy. Unsubscribe at any time.