SplitView()
import { SplitView } from '@apexnative/navigation';
SplitView puts a list and its item side by side on a big screen: the folders and the files, the mail and the
message, the settings and a section. It takes the columns, each with a stack of its own, and its methods set how they
share the width and how the sidebar shows and hides.
- iPadOS: the system's
UISplitViewController, two or three columns, and on iPadOS 26 an inspector at the trailing edge. A narrow window, when the app shares the screen, shows one column. - iOS on iPhone: one column at a time, the
compactlayout or the columns as one stack. - Android: two panes, the primary and the secondary, side by side when the width takes both (a tablet, a phone in landscape), one over the other on a narrower screen.
Usage
import { createNavigation, SplitView } from '@apexnative/navigation';
import { FoldersScreen } from './screens/Folders';
import { PickAFolderScreen } from './screens/PickAFolder';
import { FolderScreen } from './screens/Folder';
export const Navigation = createNavigation({
screens: {
Folders: FoldersScreen, // the list of folders
PickAFolder: PickAFolderScreen, // before the first pick
Folder: FolderScreen, // a picked folder
},
root: SplitView({
primary: 'Folders',
secondary: 'PickAFolder',
compact: 'Folders',
})
.displayMode('oneBesideSecondary')
.primaryColumn({ width: 320 }),
});
On iPad, Folders shows in a sidebar 320 points wide, and PickAFolder beside it. A tap on a folder calls
navigation.showInColumn('Folder', { props: { folderId } }): Folder takes PickAFolder's place. On iPhone the app
shows Folders alone, and the same call pushes Folder over it. See
Showing beside the list.
Signature
function SplitView<const Columns extends SplitViewColumns>(
columns: Columns
): SplitViewElement<UsesOf<Columns[keyof Columns]>>
SplitView takes one object with its columns, and returns a SplitViewElement. Each method returns a new one. The
screens of the columns are checked by the types where the layout is used (root, roots, switchTo).
The columns
Each column is a screen of screens by its name, Screen(…) with props, or a layout. A screen alone, by its name or
with Screen(…), gets a stack in every column but the inspector, so a column pushes and has its top bar.
primary
primary: LayoutContent
LayoutContent Required.PlatformsiOSiPadOSAndroidThe leading column: the sidebar, the list. Required.
secondary
secondary: LayoutContent
LayoutContent Required.PlatformsiOSiPadOSAndroidThe column beside the list, where a pick shows. Required. Before the first pick it needs something to show, such as a
screen that says "Pick a folder". showInColumn replaces it.
supplementary
supplementary?: LayoutContent
LayoutContentPlatformsiOSiPadOSAndroidiPadOS. A middle column, for three levels: folders, files, a file. A pick in the sidebar goes to it with
showInColumn(…, { column: 'supplementary' }).
SplitView({
primary: 'Folders',
supplementary: 'Files',
secondary: 'PickAFile',
});
Android has no middle column and leaves it out: there the split view is primary and secondary only, so a
three-column app gives Android a layout that works with two, or a compact one.
inspector
inspector?: LayoutContent
LayoutContentPlatformsiOSiPadOSAndroidiPadOS 26+. A column at the trailing edge, for facts about the item, shown and hidden with
navigation.showColumn('inspector') and hideColumn('inspector'). A screen named alone stays a screen, without a
stack. Android leaves it out.
compact
compact?: LayoutContent
LayoutContentPlatformsiOSiPadOSAndroidWhat shows where there is room for one column: iPhone, a narrow iPad window, a narrow Android screen. A layout of its own, usually the list:
SplitView({
primary: 'Folders',
secondary: 'PickAFolder',
compact: 'Folders',
});
showInColumn pushes over it there, and back returns to the list. Without compact, the columns collapse into one
stack, with compactTopColumn() on top on iOS, and on Android the secondary pane slides over the
primary one.
Where a split view goes
A split view is the root of an app most of the time: root, a name of roots, navigation.switchTo(…). It is meant
for the whole window: the columns share its width. A stack can't hold it: a stack holds screens only.
Columns on iPad
These are read by iOS only, unless the method says Android.
displayMode()
displayMode(displayMode: NonNullable<OptionsSplitView['displayMode']>): SplitViewElement<Uses>
Which columns show when the split view starts:
'oneBesideSecondary': the sidebar beside the item;'oneOverSecondary': the sidebar over the item;'secondaryOnly': the item alone;- with three columns,
'twoBesideSecondary','twoOverSecondary','twoDisplaceSecondary'; 'auto': UIKit's choice for the width, the default.
The older names 'visible', 'hidden' and 'overlay' still work.
SplitView({ primary: 'Folders', secondary: 'PickAFolder' })
.displayMode('oneBesideSecondary');
It is where the split view starts. The user changes it with the sidebar button and the swipe; the app with
navigation.showColumn and hideColumn. Each change sends splitViewDisplayModeChanged (iOS only).
splitBehavior()
splitBehavior(
splitBehavior: NonNullable<OptionsSplitView['splitBehavior']>
): SplitViewElement<Uses>
How a shown sidebar shares the width with the item:
'tile': beside it, the item narrower;'overlay': over it;'displace': pushing the item aside, partly off the screen;'automatic': UIKit's choice for the width, the default.
SplitView({ primary: 'Folders', secondary: 'PickAFolder' })
.splitBehavior('tile');
On iPadOS 26 the sidebar and the inspector float over the secondary column, which gets their room as its safe area.
primaryColumn()
primaryColumn(
column: OptionsSplitViewColumn & {
edge?: OptionsSplitView['primaryEdge'];
background?: OptionsSplitView['primaryBackgroundStyle'];
}
): SplitViewElement<Uses>
The sidebar's width and edge:
width,minWidth,maxWidth: in points. UIKit keeps the width between the two limits.edge:'leading'(the default) or'trailing', to put the sidebar on the right.background:'sidebar'gives the column the sidebar material. Mac Catalyst only.
SplitView({ primary: 'Folders', secondary: 'PickAFolder' })
.primaryColumn({ width: 320, minWidth: 280 });
Android reads width too: the width of the primary pane in dp, 360 by default. The panes are side by
side when the window is at least that width plus 360 dp wide.
supplementaryColumn()
supplementaryColumn(supplementary: OptionsSplitViewColumn): SplitViewElement<Uses>
The widths of the middle column: width, minWidth, maxWidth, in points. With a supplementary column only.
SplitView({
primary: 'Folders',
supplementary: 'Files',
secondary: 'PickAFile',
}).supplementaryColumn({ width: 360 });
inspectorColumn()
inspectorColumn(inspector: NonNullable<OptionsSplitView['inspector']>): SplitViewElement<Uses>
iPadOS 26+. The widths of the inspector column, and visible to start with it shown:
SplitView({
primary: 'Folders',
secondary: 'PickAFolder',
inspector: 'Info',
}).inspectorColumn({ width: 300, visible: false });
The inspector starts hidden; navigation.showColumn('inspector') brings it.
showsSecondaryOnlyButton()
showsSecondaryOnlyButton(showsSecondaryOnlyButton: boolean): SplitViewElement<Uses>
With three columns, a button that shows the secondary column alone, for reading at full width. Off by default.
SplitView({
primary: 'Folders',
supplementary: 'Files',
secondary: 'PickAFile',
}).showsSecondaryOnlyButton(true);
Showing and hiding the sidebar
displayModeButton()
displayModeButton(
displayModeButton: NonNullable<OptionsSplitView['displayModeButton']>
): SplitViewElement<Uses>
The button in the top bar that shows and hides the sidebar:
'automatic': UIKit's, the default; it hides the button withpresentsWithGesture(false);'always': always there;'never': never; the app shows and hides the columns itself.
SplitView({ primary: 'Folders', secondary: 'PickAFolder' })
.displayModeButton('never');
presentsWithGesture()
presentsWithGesture(presentsWithGesture: boolean): SplitViewElement<Uses>
A swipe from the edge shows the hidden sidebar. On by default; false leaves the sidebar to the button and to code.
SplitView({ primary: 'Folders', secondary: 'PickAFolder' })
.presentsWithGesture(false);
Android reads it too: with false the user can't slide the panes when one is over the other.
A phone and a narrow window
compactTopColumn()
compactTopColumn(
compactTopColumn: NonNullable<OptionsSplitView['compactTopColumn']>
): SplitViewElement<Uses>
Which column is on top when the split view has one column and no compact layout:
'primary': the list, and a pick pushes the item over it;'secondary': the item, with back to the list.
Without it, UIKit's choice on iOS, the primary pane on Android.
SplitView({ primary: 'Folders', secondary: 'Folder' })
.compactTopColumn('primary');
Android reads it as the pane that shows first on a narrow screen: with 'secondary' the secondary pane
starts over the primary one.
Other settings
options()
options(options: OptionsSplitView): SplitViewElement<Uses>
The splitView options as an object, the same keys the methods set. For options built elsewhere:
SplitView({ primary: 'Folders', secondary: 'PickAFolder' }).options({
displayMode: 'oneBesideSecondary',
width: 320,
});
The options of the screens go on the screens. Every key is in the options.
ios()
ios(build: (split: SplitViewElement<Uses>) => SplitViewElement<Uses>): SplitViewElement<Uses>
Methods for iOS only; on Android the function isn't called. For a width that differs by platform:
SplitView({ primary: 'Folders', secondary: 'PickAFolder' })
.ios((split) => split.primaryColumn({ width: 320 }))
.android((split) => split.primaryColumn({ width: 280 }));
android()
android(
build: (split: SplitViewElement<Uses>) => SplitViewElement<Uses>
): SplitViewElement<Uses>
Methods for Android only; on iOS the function isn't called. Android reads three settings: primaryColumn({ width }),
presentsWithGesture() and compactTopColumn().
Over time
- The width changes while the app runs: the user resizes the window on iPad or turns an Android phone. The split
view goes between columns and one column by itself, and the screens stay. Code that calls
showInColumndoesn't need to know which it is. - Each column keeps its stack while the others change.
showInColumnreplaces what a column shows; it doesn't push over it where there are columns. - The methods set where the split view starts. The user and
showColumn/hideColumnchange the columns later;splitViewDisplayModeChangedreports it on iOS.
See also
- Split view: showing beside the list, the sidebar, a phone and a narrow window, Android.
- List and details: a whole list-and-details app, step by step.
- The options,
Stack.