One Logo Pool Ball
wwwwwwwwwwwwwwwwwww

iOS Tabs and Pager

Tabs, Tab, TabSection, TabViewSlot, TabViewBottomAccessory, Pager, and Page under One.iOS

One.iOS Tabs with a glass tab bar, a badge, a search tab, and a now playing accessory

Tab navigation and swipe paging under One.iOS, drawn by SwiftUI.

Tabs

One.iOS.Tabs is a SwiftUI tab view. Only Tab, TabSection, TabViewSlot, and TabViewBottomAccessory may be its direct children.

Each tab’s navigation container is transparent on iOS 18 and later, so the system bar can show the content behind it. Your page owns its background.

import { One } from 'one'
<One.iOS.Tabs selection={tab} onSelectionChange={setTab}>
<One.iOS.Tab id="feed" title="Feed" systemImage="house">
<FeedScreen />
</One.iOS.Tab>
<One.iOS.Tab id="new" title="New" systemImage="plus" onPress={openComposer} />
</One.iOS.Tabs>
PropsTypeDescription
selection (required)stringThe id of the selected page tab.
stringThe id of the selected page tab.
onSelectionChange (required)(id: string) => voidA native tab change, with the new id.
(id: string) => voidA native tab change, with the new id.
onReselect(id: string) => voidA tap on the selected tab outside a TabSection, with its id.
(id: string) => voidA tap on the selected tab outside a TabSection, with its id.
revisionnumber = 0Increase with a new selection to reset it from outside.
number = 0Increase with a new selection to reset it from outside.
tabViewStyleTabViewStyle = "automatic"automatic, sidebarAdaptable, tabBarOnly, or page.
TabViewStyle = "automatic"automatic, sidebarAdaptable, tabBarOnly, or page.
tabBarVisibilityVisibility = "automatic"The tab bar on every page: automatic, visible, or hidden.
Visibility = "automatic"The tab bar on every page: automatic, visible, or hidden.
customizationstring = ""Saved tab customization JSON, from onCustomizationChange.
string = ""Saved tab customization JSON, from onCustomizationChange.
onCustomizationChange(customization: string) => voidPeople reordered or hid tabs. Persist the JSON.
(customization: string) => voidPeople reordered or hid tabs. Persist the JSON.
swiftStyleOneNativeStyleSwiftUI modifiers on the tab view.
OneNativeStyleSwiftUI modifiers on the tab view.
children (required)ReactNodeTab, TabSection, TabViewSlot, and TabViewBottomAccessory elements.
ReactNodeTab, TabSection, TabViewSlot, and TabViewBottomAccessory elements.

selection must name a mounted page tab, or Tabs throws. Sections, tab modifiers, styles, and customization need iOS 18.

Tab

One.iOS.Tab is one tab. It takes either children, as a page, or onPress, as an action tab, never both. Ids must be unique and nonempty.

PropsTypeDescription
id (required)stringIdentifies the tab in selection.
stringIdentifies the tab in selection.
title (required)stringThe tab label.
stringThe tab label.
systemImagestringAn SF Symbol. Not with image.
stringAn SF Symbol. Not with image.
imagestringAn asset catalog image. Not with systemImage.
stringAn asset catalog image. Not with systemImage.
labelStyleSDKLabelStyleiconOnly keeps the title for VoiceOver only.
SDKLabelStyleiconOnly keeps the title for VoiceOver only.
badgestring | numberA badge on the tab item.
string | numberA badge on the tab item.
roleTabRolesearch or prominent, the SwiftUI tab roles.
TabRolesearch or prominent, the SwiftUI tab roles.
tabPlacementTabPlacementautomatic, pinned, or sidebarOnly.
TabPlacementautomatic, pinned, or sidebarOnly.
testIDstringIdentifies the page in tests.
stringIdentifies the page in tests.
onPress() => voidMakes an action tab, which runs this and keeps the selection.
() => voidMakes an action tab, which runs this and keeps the selection.
swiftStyleOneNativeStyleSwiftUI modifiers on the page content.
OneNativeStyleSwiftUI modifiers on the page content.
childrenReactNodeThe page.
ReactNodeThe page.

Tab and TabSection share these SwiftUI tab modifiers:

ModifiersTypeDescription
disabledbooleanDims the tab. iOS 18.4 or later.
booleanDims the tab. iOS 18.4 or later.
hiddenbooleanRemoves the tab from the bar and sidebar.
booleanRemoves the tab from the bar and sidebar.
customizationIDstringLets people reorder or hide the tab.
stringLets people reorder or hide the tab.
customizationBehavior{ behavior: TabCustomizationBehavior for?: readonly AdaptableTabBarPlacement[] }automatic, reorderable, or disabled, for the listed placements.
{ behavior: TabCustomizationBehavior for?: readonly AdaptableTabBarPlacement[] }automatic, reorderable, or disabled, for the listed placements.
defaultVisibility{ visibility: Visibility for?: readonly AdaptableTabBarPlacement[] }Shown or hidden until people customize, for the listed placements.
{ visibility: Visibility for?: readonly AdaptableTabBarPlacement[] }Shown or hidden until people customize, for the listed placements.
springLoadingBehaviorSpringLoadingBehaviorWhether a drag hovering the tab opens it.
SpringLoadingBehaviorWhether a drag hovering the tab opens it.
accessibilityLabelstringRead by VoiceOver in place of the title.
stringRead by VoiceOver in place of the title.
accessibilityHintstringWhat selecting the tab does.
stringWhat selecting the tab does.
accessibilityValuestringThe tab's current value.
stringThe tab's current value.
accessibilityIdentifierstringIdentifies the tab item in UI tests.
stringIdentifies the tab item in UI tests.
helpstringHelp text for the tab. iOS 27 or later.
stringHelp text for the tab. iOS 27 or later.

TabSection

One.iOS.TabSection groups tabs under a heading in the sidebar. Its children are Tab elements, at least one.

PropsTypeDescription
id (required)stringIdentifies the section.
stringIdentifies the section.
title (required)stringThe section heading.
stringThe section heading.
defaultSectionExpansionTabSectionExpansionautomatic, expanded, or collapsed at first.
TabSectionExpansionautomatic, expanded, or collapsed at first.
sectionActionsreadonly { id: string title: string systemImage?: string onPress: () => void }[]Buttons in the section header.
readonly { id: string title: string systemImage?: string onPress: () => void }[]Buttons in the section header.
children (required)ReactNodeThe tabs.
ReactNodeThe tabs.

TabViewSlot

One.iOS.TabViewSlot fills a named tab view slot with React Native content.

PropsTypeDescription
name (required)TabViewSlotNametabViewBottomAccessory (iOS 26), or a sidebar slot (iOS 18).
TabViewSlotNametabViewBottomAccessory (iOS 26), or a sidebar slot (iOS 18).
height (required)numberThe slot height in points. Must be above zero.
numberThe slot height in points. Must be above zero.
children (required)ReactNodeThe slot content.
ReactNodeThe slot content.

The sidebar slots are tabViewSidebarHeader, tabViewSidebarFooter, and tabViewSidebarBottomBar. Each name may appear once. The three sidebar slots display only when the tab view presents a sidebar; they are absent from the compact iPhone tab bar. Place it directly inside Tabs, alongside the Tab children. The bottom accessory remains above the system tab bar as selection changes; its React Native children keep their event handlers.

On iPad, use tabViewStyle="sidebarAdaptable" to present the native sidebar. tabViewSidebarHeader and tabViewSidebarFooter sit above the sidebar bottom bar; tabViewSidebarBottomBar spans the bottom of the sidebar. Each slot keeps its declared height and React Native actions when the sidebar is open. Selecting a tab closes the sidebar on iPad; reopening it shows the slots for the selected tab.

import { One } from 'one'
import { Pressable, Text } from 'react-native'
<One.iOS.Tabs selection={tab} onSelectionChange={setTab}>
<One.iOS.Tab id="home" title="Home" systemImage="house">...</One.iOS.Tab>
<One.iOS.Tab id="other" title="Other" systemImage="star">...</One.iOS.Tab>
<One.iOS.TabViewSlot name="tabViewBottomAccessory" height={50}>
<Pressable onPress={openPlayer}><Text>Open player</Text></Pressable>
</One.iOS.TabViewSlot>
</One.iOS.Tabs>
<One.iOS.Tabs tabViewStyle="sidebarAdaptable" selection={tab} onSelectionChange={setTab}>
<One.iOS.Tab id="home" title="Home" systemImage="house">...</One.iOS.Tab>
<One.iOS.Tab id="other" title="Other" systemImage="star">...</One.iOS.Tab>
<One.iOS.TabViewSlot name="tabViewSidebarHeader" height={44}>
<Pressable onPress={openSearch}><Text>Search</Text></Pressable>
</One.iOS.TabViewSlot>
<One.iOS.TabViewSlot name="tabViewSidebarFooter" height={48}>
<Pressable onPress={openSettings}><Text>Settings</Text></Pressable>
</One.iOS.TabViewSlot>
<One.iOS.TabViewSlot name="tabViewSidebarBottomBar" height={52}>
<Pressable onPress={openProfile}><Text>Profile</Text></Pressable>
</One.iOS.TabViewSlot>
</One.iOS.Tabs>

TabViewBottomAccessory

One.iOS.TabViewBottomAccessory sits above the tab bar, like a music player’s now playing bar. It needs iOS 26, and Tabs takes one.

PropsTypeDescription
isEnabledbooleanHides the accessory without remounting it. iOS 26.1 or later.
booleanHides the accessory without remounting it. iOS 26.1 or later.
childrenReactNodeContent for both layouts.
ReactNodeContent for both layouts.
inlineReactNodeContent while the bar is minimized beside it.
ReactNodeContent while the bar is minimized beside it.
expandedReactNodeContent above the full bar.
ReactNodeContent above the full bar.

It needs children, inline, or expanded. A missing layout falls back to the others.

Pager, Page

One.iOS.Pager is a tab view without the bar: people swipe between pages. Children must be Page elements with unique nonempty ids, and selection must name a mounted page. For a pager on both platforms, use One.UI.Pager.

import { One } from 'one'
<One.iOS.Pager selection={page} onSelectionChange={setPage}>
<One.iOS.Page id="one">...</One.iOS.Page>
<One.iOS.Page id="two">...</One.iOS.Page>
</One.iOS.Pager>
PagerTypeDescription
selection (required)stringThe id of the shown page.
stringThe id of the shown page.
onSelectionChange (required)(id: string) => voidA swipe to another page.
(id: string) => voidA swipe to another page.
revisionnumber = 0Increase with a new selection to reset it from outside.
number = 0Increase with a new selection to reset it from outside.
children (required)ReactNodePage elements.
ReactNodePage elements.
PageTypeDescription
id (required)stringIdentifies the page in selection.
stringIdentifies the page in selection.
testIDstringIdentifies the page in tests.
stringIdentifies the page in tests.
children (required)ReactNodeThe page content.
ReactNodeThe page content.

Edit this page on GitHub.