Skip to main content
‹ Split view
Function

SplitView()

SectionSplit viewDraftDocumented, not reviewed yet: the API can change.
Import
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 compact layout 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.
iPadOS

Usage​

src/Navigation.ts
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]>>
Defined in src/api/layout/SplitView.ts ↗

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
TypeLayoutContent Required.PlatformsiOSiPadOSAndroid

The leading column: the sidebar, the list. Required.

secondary​

secondary: LayoutContent
TypeLayoutContent Required.PlatformsiOSiPadOSAndroid

The 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
TypeLayoutContentPlatformsiOSiPadOSAndroid

iPadOS. 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
TypeLayoutContentPlatformsiOSiPadOSAndroid

iPadOS 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
TypeLayoutContentPlatformsiOSiPadOSAndroid

What 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>
PlatformsiOSiPadOSAndroid

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>
PlatformsiOSiPadOSAndroid

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>
PlatformsiOSiPadOSAndroid

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>
PlatformsiOSiPadOSAndroid

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>
PlatformsiOSiPadOSAndroid

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>
PlatformsiOSiPadOSAndroid

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);

displayModeButton()​

displayModeButton(
displayModeButton: NonNullable<OptionsSplitView['displayModeButton']>
): SplitViewElement<Uses>
PlatformsiOSiPadOSAndroid

The button in the top bar that shows and hides the sidebar:

  • 'automatic': UIKit's, the default; it hides the button with presentsWithGesture(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>
PlatformsiOSiPadOSAndroid

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>
PlatformsiOSiPadOSAndroid

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>
PlatformsiOSiPadOSAndroid

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>
PlatformsiOSiPadOSAndroid

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>
PlatformsiOSiPadOSAndroid

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 showInColumn doesn't need to know which it is.
  • Each column keeps its stack while the others change. showInColumn replaces 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 / hideColumn change the columns later; splitViewDisplayModeChanged reports it on iOS.

See also​

Generated from the types and their comments. Edit the source ↗