---
modificationDate: May 06, 2026
title: Router Split View
description: An Expo Router submodule that provides native split view layout.
sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-56/packages/expo-router'
packageName: 'expo-router'
platforms: ['ios']
isAlpha: true
---

<AgentInstructions>

## Submitting Feedback

If this page contains errors, outdated information, or gaps that blocked you from completing a task, report it so the docs can be improved:

curl -X POST https://api.expo.dev/v2/feedback/docs-send -H 'Content-Type: application/json' -d '{"url":"/versions/v56.0.0/sdk/router/split-view/","feedback":"🤖 Agent feedback: <specific, actionable description>"}'

Only submit when you have something specific and actionable to report.

</AgentInstructions>

# Expo Router Split View

An Expo Router submodule that provides native split view layout.
iOS

> For the complete documentation index, see [llms.txt](/llms.txt). Use this file to discover all available pages.

> SplitView is an [alpha](/more/release-statuses#alpha) API available on **iOS only** in **Expo SDK 55** and later. The API is subject to breaking changes and is not ready for production usage yet.

`expo-router/unstable-split-view` is a submodule of `expo-router` and exports components to build split view layouts using [platform-native system split views](https://developer.apple.com/design/human-interface-guidelines/split-views).

> See the [Expo Router](/versions/v56.0.0/sdk/router/index) reference for more information about the file-based routing library for native and web app.

## Platform support

Split View is only available on iOS. On other platforms, the `SplitView` component automatically falls back to rendering as a standard `Slot` navigator, ensuring your app works across all platforms without conditional code.

## iPhone support

On iPhone, `SplitView` automatically collapses all columns into a single view. Only one column is visible at a time.

### Choosing the initial column

Use the `topColumnForCollapsing` prop to control which column is displayed when the split view is collapsed:

```tsx
<SplitView topColumnForCollapsing="primary">{/* ... */}</SplitView>
```

Accepted values are `primary`, `supplementary`, and `secondary`. When not set, the system uses its default behavior.

### Navigating between columns

> The `.show()` method requires `react-native-screens` 4.24.0 or later. SDK 55 bundles `~4.23.0`, so you need to install `react-native-screens@~4.24.0` manually to use this feature.

Use a `ref` to programmatically show a specific column with the `show` method:

```tsx
import { useRef } from 'react';
import { Pressable, Text } from 'react-native';
import { SplitView } from 'expo-router/unstable-split-view';
import type { SplitHostCommands } from 'react-native-screens/experimental';

export default function Layout() {
  const ref = useRef<SplitHostCommands>(null);

  return (
    <SplitView ref={ref} topColumnForCollapsing="primary">
      <SplitView.Column>
        <Pressable onPress={() => ref.current?.show('secondary')}>
          <Text>Show main content</Text>
        </Pressable>
      </SplitView.Column>
    </SplitView>
  );
}
```

## Known limitations

Cannot be nested

There can only be one `SplitView` in the navigation hierarchy. Attempting to nest split views will result in an error.

Cannot be used inside other navigators

`SplitView` cannot be used inside another navigator (except for `Slot`). It must be used at the root layout level.

Only specific children allowed

`SplitView` only accepts `SplitView.Column` and `SplitView.Inspector` as direct children. Other components will be ignored with a warning.

Header cannot be customized yet

The header (navigation bar) within split view columns cannot be customized. Custom header configurations are not yet supported.

Limited API

The current API surface is minimal and may not cover all use cases. Additional props and configuration options will be added in future releases.

Going back to previous column on iPhone

To go back to a previous column, tap the system back button in the navigation bar. A future release will add more granular programmatic control over back navigation.

> **Note:** We are actively developing `SplitView` and looking for feedback. You can share your thoughts on [Discord](https://chat.expo.dev), [open an issue on GitHub](https://github.com/expo/expo/issues), or use the **Feedback** button at the bottom of this page.

## Installation

To use `expo-router/unstable-split-view` in your project, you need to install `expo-router` in your project. Follow the instructions from Expo Router's installation guide:

[Install Expo Router](/router/installation) — Learn how to install Expo Router in your project.

## Using `SplitView.Column`

`SplitView.Column` defines additional columns in your split view layout. You can add up to two columns before the main content area.

### Two-column layout

A simple sidebar with main content:

```tsx
import { Link } from 'expo-router';
import { SplitView } from 'expo-router/unstable-split-view';
import { Text, Pressable } from 'react-native';
import { SafeAreaView } from 'react-native-screens/experimental';

export default function Layout() {
  return (
    <SplitView>
      <SplitView.Column>
        <SafeAreaView edges={{ left: true, top: true }} style={{ flex: 1 }}>
          <Link href="/inbox">
            <Pressable style={{ padding: 16 }}>
              <Text>Inbox</Text>
            </Pressable>
          </Link>
          <Link href="/sent">
            <Pressable style={{ padding: 16 }}>
              <Text>Sent</Text>
            </Pressable>
          </Link>
        </SafeAreaView>
      </SplitView.Column>
    </SplitView>
  );
}
```

### Three-column layout

A sidebar with supporting column and main content:

```tsx
import { Link, useGlobalSearchParams } from 'expo-router';
import { SplitView } from 'expo-router/unstable-split-view';
import { SafeAreaView } from 'react-native-screens/experimental';

export default function Layout() {
  const params = useGlobalSearchParams();

  return (
    <SplitView>
      <SplitView.Column>
        <SafeAreaView
          edges={{ left: true, top: true }}
          style={{
            flex: 1,
            gap: 16,
            padding: 16,
          }}>
          <Link href="/?col1=1" style={{ fontWeight: params.col1 === '1' ? 'bold' : 'normal' }}>
            Option 1
          </Link>
          <Link href="/?col1=2" style={{ fontWeight: params.col1 === '2' ? 'bold' : 'normal' }}>
            Option 2
          </Link>
          <Link href="/?col1=3" style={{ fontWeight: params.col1 === '3' ? 'bold' : 'normal' }}>
            Option 3
          </Link>
        </SafeAreaView>
      </SplitView.Column>
      <SplitView.Column>
        <SafeAreaView
          edges={{ left: true, top: true }}
          style={{
            flex: 1,
            gap: 16,
            padding: 16,
          }}>
          <Link href={`/?col1=${params.col1}&col2=1`}>Sub-Option 1</Link>
          <Link href={`/?col1=${params.col1}&col2=2`}>Sub-Option 2</Link>
          <Link href={`/?col1=${params.col1}&col2=3`}>Sub-Option 3</Link>
        </SafeAreaView>
      </SplitView.Column>
    </SplitView>
  );
}
```

## Using `SplitView.Inspector`

`SplitView.Inspector` adds a supplementary column that slides in from the trailing edge, useful for showing additional details or metadata:

```tsx
<SplitView>
  <SplitView.Column>{/* Sidebar */}</SplitView.Column>
  <SplitView.Inspector>
    <View style={{ flex: 1, padding: 16 }}>
      <Text>Inspector Panel</Text>
    </View>
  </SplitView.Inspector>
</SplitView>
```

## Complete example

Here's a password manager-style app with three columns:

`app`

 `_layout.tsx`

 `index.tsx`

 `[type]`

  `[id].tsx`

  `index.tsx`

```tsx
import { Link, Color, useGlobalSearchParams } from 'expo-router';
import { SplitView } from 'expo-router/unstable-split-view';
import { Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
import { SafeAreaView } from 'react-native-screens/experimental';

export default function Layout() {
  return (
    <SplitView showInspector>
      <SplitView.Column>
        <PasscodeList />
      </SplitView.Column>
      <SplitView.Column>
        <PasswordElementList />
      </SplitView.Column>
      <SplitView.Inspector>
        <InspectorContent />
      </SplitView.Inspector>
    </SplitView>
  );
}

function PasscodeList() {
  return (
    <SafeAreaView edges={{ top: true, left: true }} style={style.passcodeList}>
      <PasscodeCard title="All" param="all" />
      <PasscodeCard title="Passkeys" param="passkeys" />
      <PasscodeCard title="Codes" param="codes" />
      <PasscodeCard title="Security" param="security" />
      <PasscodeCard title="Deleted" param="deleted" />
    </SafeAreaView>
  );
}

const passkeys = ['Github', 'Google', 'Facebook', 'Twitter', 'Apple', 'Microsoft', 'Amazon'];
const security = ['Admin1234', 'Root'];

const all = [...passkeys, ...security];

function PasswordElementList() {
  const params = useGlobalSearchParams();
  const data = (() => {
    switch (params.type) {
      case 'all':
      case undefined:
        return all;
      case 'passkeys':
        return passkeys;
      case 'security':
        return security;
      default:
        return [];
    }
  })();
  return (
    <ScrollView contentInsetAdjustmentBehavior="automatic" style={{ backgroundColor: undefined }}>
      {data.map(item => (
        <PasswordElement key={item} title={item} />
      ))}
    </ScrollView>
  );
}

function PasscodeCard({ param, title }: { param: string; title: string }) {
  const params = useGlobalSearchParams();
  const isActive = params.type === param;
  return (
    <Link
      href={`/${param}/`}
      disabled={isActive}
      style={[
        style.passcodeCard,
        {
          backgroundColor: isActive ? Color.ios.systemBlue : Color.ios.systemGray6,
        },
      ]}
      asChild>
      <Pressable>
        <Text style={{ color: isActive ? 'white' : 'black', fontSize: 16 }}>{title}</Text>
      </Pressable>
    </Link>
  );
}

function PasswordElement({ title }: { title: string }) {
  const params = useGlobalSearchParams();
  const isActive = params.id === title;
  return (
    <Link href={`/${params.type}/${title}/`} asChild>
      <Pressable
        style={{
          backgroundColor: isActive ? Color.ios.systemBlue : undefined,
          padding: 12,
        }}>
        <SafeAreaView edges={{ left: true }}>
          <Text style={{ color: isActive ? 'white' : 'black', fontSize: 16 }}>{title}</Text>
        </SafeAreaView>
      </Pressable>
    </Link>
  );
}

function InspectorContent() {
  return (
    <View style={style.inspectorContent}>
      <Text>Inspector</Text>
    </View>
  );
}

const style = StyleSheet.create({
  passcodeList: {
    flex: 1,
    flexWrap: 'wrap',
    gap: 8,
    flexDirection: 'row',
    padding: 8,
  },
  passcodeCard: {
    width: '48%',
    padding: 12,
    borderRadius: 12,
    justifyContent: 'center',
    alignItems: 'center',
    height: 50,
  },
  inspectorContent: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});
```

```tsx
import { Redirect } from 'expo-router';

export default function Index() {
  return <Redirect href="/all/" />;
}
```

```tsx
import { Color } from 'expo-router';
import { Text, View } from 'react-native';

export default function Index() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text style={{ color: Color.ios.label, fontSize: 24, fontWeight: 'bold' }}>
        Nothing is selected
      </Text>
    </View>
  );
}
```

```tsx
import { useLocalSearchParams } from 'expo-router';
import { Text, View } from 'react-native';

export default function Id() {
  const { id } = useLocalSearchParams();

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>ID: {id}</Text>
    </View>
  );
}
```

## API

```js
import { SplitView } from 'expo-router/unstable-split-view';
```

## Components

### `SplitView`

Supported platforms: iOS.

Type: React.[Element](https://www.typescriptlang.org/docs/handbook/jsx.html#function-component)<[SplitViewProps](#splitviewprops)\>

For full list of supported props, see [`SplitHostProps`](http://github.com/software-mansion/react-native-screens/blob/main/src/components/gamma/split/SplitHost.types.ts#L117)

SplitViewProps

### `children`

Supported platforms: iOS.

Optional • Type: [ReactNode](https://reactnative.dev/docs/react-node)

#### Inherited Props

-   [Omit](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys)<SplitHostProps, 'children'\>

### `SplitView.Column`

Supported platforms: iOS.

Type: React.[Element](https://www.typescriptlang.org/docs/handbook/jsx.html#function-component)<[SplitViewColumnProps](#splitviewcolumnprops)\>

SplitViewColumnProps

### `children`

Supported platforms: iOS.

Optional • Type: [ReactNode](https://reactnative.dev/docs/react-node)

### `SplitView.Inspector`

Supported platforms: iOS 26+.

Type: React.[Element](https://www.typescriptlang.org/docs/handbook/jsx.html#function-component)<[SplitViewColumnProps](#splitviewcolumnprops)\>
