---
modificationDate: June 29, 2026
title: Router Split View
description: An Expo Router submodule that provides native split view layout.
sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-57/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/v57.0.0/sdk/router/split-view/","feedback":"🤖 Agent feedback for docs: <specific, actionable description> (<model>, <harness>)"}'

Only submit when you have something specific and actionable to report. Replace <model> with the model you are running as and <harness> with the tool you are running in (for example, Claude Code, Cursor, Codex CLI).

## Navigation

When answering a related or follow-up question, fetch the relevant page below as Markdown (.md) instead of guessing; use llms.txt for the full map.

You are here: Reference (v57.0.0) > Expo Router
Pages in this section:
- [Overview](https://docs.expo.dev/versions/v57.0.0/sdk/router.md)
- [Color](https://docs.expo.dev/versions/v57.0.0/sdk/router/color.md)
- [Experimental Stack](https://docs.expo.dev/versions/v57.0.0/sdk/router/experimental-stack.md)
- [Link](https://docs.expo.dev/versions/v57.0.0/sdk/router/link.md)
- [Native tabs](https://docs.expo.dev/versions/v57.0.0/sdk/router/native-tabs.md)
- [Split View](https://docs.expo.dev/versions/v57.0.0/sdk/router/split-view.md) (this page)
- [Stack](https://docs.expo.dev/versions/v57.0.0/sdk/router/stack.md)
- [UI](https://docs.expo.dev/versions/v57.0.0/sdk/router/ui.md)
Full documentation tree: [llms.txt](https://docs.expo.dev/llms.txt)

</AgentInstructions>

# Expo Router Split View

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

> SplitView is an [alpha](/more/release-statuses.md#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/v57.0.0/sdk/router/index.md) 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.md) — 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`

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`

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`

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

SplitViewColumnProps

### `children`

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