suiss/uim · Pattern

Split View

Sidebar, list and detail columns side by side on wide screens, shown one at a time with back navigation on phones.

Split View is an open-source mobile pattern from suiss/uim: components composed into a flow for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.

iOS
Split View on iOS in light mode

SplitView lays out up to three panes: SplitViewSidebar, SplitViewList and SplitViewDetail. When the window is at least breakpoint wide (768 by default), they sit side by side in a bordered row, sized 20, 32 and 48 parts.

Below the breakpoint only the current column is shown, full screen and scrollable, with a large title. Pressing a SplitViewItem moves to the next column, and a back button titled with the previous pane returns to it. On Android the hardware back button also goes back. Use it for mail, notes or settings screens that drill down.

Installation

$ pnpm dlx @esuiss/uim@latest add split-view

The CLI also adds what it builds on: Icon, Text.

Manual

  1. Install the dependencies:
npx expo install cn phosphor-react-native react-native-reanimated react-native-svg react-native-worklets
  1. Add the pieces it builds on: Icon, Text, and the primitives components/primitives/hooks.tsx.

  2. Copy the source into components/patterns/split-view.tsx:

uniwind/components/patterns/split-view.tsx
import { cn } from "cn"
import { CaretLeftIcon, CaretRightIcon } from "phosphor-react-native"
import * as React from "react"
import {
  AccessibilityInfo,
  I18nManager,
  Pressable,
  type Text as RNText,
  ScrollView,
  useWindowDimensions,
  View,
  type ViewProps,
} from "react-native"
import { FadeIn, ReduceMotion } from "react-native-reanimated"
import { useBackHandler } from "@/components/primitives/hooks"
import { AnimatedView } from "@/components/ui/animated-view"
  1. Update the import paths to match your project.

Usage

import { SplitView, SplitViewSidebar, SplitViewList, SplitViewDetail, SplitViewItem } from "@/components/patterns/split-view"
<MailExample />

Give each pane a title; the back button only appears when the previous pane exists and has a title. Put SplitViewItems in the sidebar and list panes, and use their onPress to set the selection in your own state.

The current column is uncontrolled with defaultColumn (list by default) or controlled with column and onColumnChange. useSplitView returns isCompact, column and setColumn for custom navigation.

Examples

Detail column

Starts on the detail column.

iOS
Split View (detail column) on iOS in light mode

Start on sidebar

Starts on the sidebar column.

iOS
Split View (start on sidebar) on iOS in light mode

Two columns

Only list and detail panes, without a sidebar.

iOS
Split View (two columns) on iOS in light mode

Wide

Sets breakpoint to 0 to always show the columns side by side.

iOS
Split View (wide) on iOS in light mode

Wide two columns

Side-by-side list and detail panes without a sidebar.

iOS
Split View (wide two columns) on iOS in light mode

API Reference

SplitView

The root that tracks the current column and the layout mode.

ExtendsViewProps
PropType
About
The visible column on phones when controlled: sidebar, list or detail.
Type
SplitViewColumn
Default
—
About
The initial column when uncontrolled. Defaults to list.
Type
SplitViewColumn
Default
"list"
About
Called with the new column.
Type
(column: SplitViewColumn) => void
Default
—
About
Window width at which the panes sit side by side. Defaults to 768.
Type
number
Default
768

SplitViewSidebar

The first pane, for top-level sections.

ExtendsSplitViewPaneProps

SplitViewList

The middle pane, for the items in a section.

ExtendsSplitViewPaneProps

SplitViewDetail

The last pane, for the selected item.

ExtendsSplitViewPaneProps

SplitViewItem

A pressable row that moves to the next column.

ExtendsReact.ComponentProps<typeof Pressable>
PropType
About
Highlights the row and marks it as selected.
Type
boolean
Default
false
Type
React.ReactNode
Default
—

Accessibility

  • Pane titles have the heading role, and panes are labelled by string titles.
  • On phones, screen reader focus moves to the new pane's heading after navigating.
  • SplitViewItem exposes its selected state.
  • Back and row chevrons mirror in right-to-left layouts.

Notes

  • On phones the new pane fades in, respecting the system reduce motion setting.
  • Active rows use bg-surface-secondary; panes are divided by border-separator.