Getting Started
A tab bar lets your users navigate between top-level sections of your app. Each tab in the tab bar represents a different, distinct section or feature of your app. Use a tab bar to provide navigation, and not provide actions within your app.
Creating a Tab
To create a tab bar with tabs, first create a TabView
. Then, create a Tab
within the TabView
.

Creating a Search Tab
A TabRole
is a value that defines the purpose of the tab. Currently, there is only one TabRole
—the search role. Tab views will prefer to have the first tab with the search role implement search. If no tabs are specified as the search tab, the tab view will apply search to all tabs, resetting search state as the selected tab changes.
To create a search tab, simply populate the role argument with .search
. The .search
TabRole
by default provides a magnifying glass SF Symbol in the tab bar.
Implementing this into our TabView will give us the following result:

Programmatically Switch Tabs
Within the initialiser for a tab view, there's a selection:
argument that takes in a Binding SelectionValue. The selection:
argument updated the Binding SelectionValue when you navigate between tabs, updating the value to the currently selected tab. This also means that we can modify the Binding SelectionValue to programmatically switch between tabs, and set the default tab that opens.
First, create an enum called TabSelection
, with a case for each of your tabs as shown in the example below.
Next, create a State variable of type TabSelection
, and assign it to the tab you want to present when the app first launches. In this case, it'll be the cuisine tab.
Afterwards, bind selectedTab
State variable's value to the selection:
argument.
Then, assign the value:
argument with a case from TabSelection
for each of your tabs. Take note that the value:
argument precedes the role:
argument for tabs that are initialised using TabRole
.
Putting everything together, you'll get this:
Launching the app, it'll look like this:

If you wish to programmatically switch and navigate between tabs, you can assign the selection:
argument's value to another case in your enum.

Going Further
Exploring SidebarAdaptable Style
Starting in iOS 18 and iPadOS 18, tab views have a new style called SidebarAdaptable. The SidebarAdaptable style behaves differently depending on the platform. On iOS, it always displays as a bottom bar. While on iPadOS, it displays as a displays a top tab bar that can adapt into a sidebar.
To make your tab bar on iPadOS adapt into a sidebar, you can use the .tabViewStyle
modifier and populate it with the .sidebarAdaptable
style, as shown in the example below.

Styling the Sidebar
Apple has provided three modifiers to configure and extra content to the sidebar.
The first modifier is .tabViewSidebarHeader
. This places a view on top of the list of tabs in your sidebar. In the example below, it shows the text "Main Tabs" above the list of tabs.

The second modifier is .tabViewSidebarFooter
. This places a view below the list of tabs in your sidebar. In the example below, it shows a copyright text below the list of tabs.

The third modifier is .tabViewSidebarBottomBar
. This places inside the bottom bar region of your sidebar. In the example below, it shows a user account in the bottom bar of the sidebar.

Creating Tab Sections
TabSection
helps to organise tabs into separate sections. Each section has custom tab content that you provide on a per-instance basis. You can also provide a header for each of the sections. Tab sections default to the last presented tab in the section. If the app has just launched, it defaults to the first tab in the section.
Do note that TabSection
does not work if you have a value passed into the selection:
argument for your TabView
.
The code below separates out all the cuisines into tabs in a tab section.

Styling Tab Sections
You can set the default visibility for a tab section using the .defaultVisibility
modifier. As shown in the example below, this can be useful if you want to only show the tab section within the sidebar, and not in the tab bar.

You're also able to add views to the end of a section using the .sectionAction
modifier. Typically, buttons are added to the end of a section to perform an action relevant to that section.

Enabling Tab Customisation
Tab bars can also be made user customisable, allowing users to add, remove, and reorganise the tabs to their liking. To enable tab customisation, first create an AppStorage variable of type TabViewCustomization
. An AppStorage property wrapper is being used instead of a State property wrapper to persist the customisations made by the user, even when the app has been quit.
Then, use the .tabViewCustomization
modifier and bind your variable to it.
Lastly, add a customisation ID using the .customizationID
modifier to every single tab, including the ones within tab sections. Each customisation ID should be unique.
After that, you will be able to customise your tab bar and sidebar simply by toggling or dragging the tabs around.
Exploring Page Style
The Page tab view style displays a paged scrolling TabView, allowing you to swipe through multiple views/pages, with page indicators at the bottom to let you know where you are in the pages.
To present a paged scrolling TabView, you can use the .tabViewStyle
modifier and populate it with the .page
style, as shown in the example below.

Styling Page Index
There are two ways you're able to style your page index for page tab style views. First, is to set the index display mode using the indexDisplayMode:
argument in the .page
tab view style.
Setting the argument to .always
will always show the page index, while setting it to .never
will never show the page index. By default, it's set to .automatic
.
Next, you can also set the background display mode for your page index by using the .indexViewStyle
modifier, and setting the backgroundDisplayMode:
argument for the .page
tab view style.
Setting the argument to .always
will always show the page index background, setting it to .interactive
will only show the page index background when you're swiping between pages, and setting it to .never
will never show the page index background. By default, it's set to .automatic
.

In These Collections
This article can also be found in these collections.