Skip to main content
RapidDev - Software Development Agency
App Featurespersonalization-ux14 min read

How to Add Split Screen to Your App — Copy-Paste Prompts Included

A split-screen layout needs a drag library (react-resizable-panels), a resize handle, and localStorage to remember the user's ratio. With Lovable or V0 you can ship a working split view in 2–3 hours at $0/month — everything runs client-side. Complexity only grows when you need nested panels, cross-device sync, or components like maps that must be told their container changed size.

4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members

Feature spec

Intermediate

Category

personalization-ux

Build with AI

2–4 hours with Lovable or V0

Custom build

2–5 days custom dev

Running cost

$0/mo (optionally $0–25/mo if syncing layout to Supabase)

Works on

Web

Everything it takes to ship Split Screen — parts, prompts, and real costs.

TL;DR

A split-screen layout needs a drag library (react-resizable-panels), a resize handle, and localStorage to remember the user's ratio. With Lovable or V0 you can ship a working split view in 2–3 hours at $0/month — everything runs client-side. Complexity only grows when you need nested panels, cross-device sync, or components like maps that must be told their container changed size.

What a Split-Screen Feature Actually Is

A split-screen layout divides the viewport into two independently scrollable, resizable panels separated by a draggable handle. Editors use it for source and preview, translation tools for original and output, diff views for old and new versions. The drag library handles sizing and constraints; the real product decisions are what lives in each panel, how to handle components that don't know their container changed size, and whether to persist the user's ratio across sessions. Most apps need exactly two panels — the VS Code four-panel grid is the rare exception, not the starting point.

What users consider table stakes in 2026

  • Drag handle is at least 8px wide with a visible hover/active state so users know it is grabbable
  • Minimum panel width (200px or 20%) prevents either panel from collapsing to zero during a drag
  • Split ratio persists across page reloads via localStorage so users don't re-tune every session
  • Collapse/expand buttons let users temporarily hide one panel entirely with one click
  • Keyboard users can focus the resize handle and nudge it with arrow keys
  • On mobile, panels stack vertically and the drag handle disappears — no broken layout on small screens
  • Inner components (charts, maps, iframes) are notified when their panel resizes so they can reflow content

Anatomy of the Feature

Seven components, five of which AI tools generate correctly on the first prompt. ResizeObserver notification and keyboard accessibility are where first builds usually miss.

Layers:UIData

Split container

UI

The outer flex container that hosts both panels and the divider. Built with react-resizable-panels (PanelGroup component) or react-split (split.js). Renders children as siblings with a draggable bar between them and emits an onLayout callback with updated size percentages after each drag.

Note: Prefer react-resizable-panels over react-split for new projects — it uses Pointer Events API (works on touch), ships TypeScript types, and exposes a ref-based API for programmatic collapse.

Resize handle

UI

The vertical bar users drag to change the panel ratio. PanelResizeHandle from react-resizable-panels handles all pointer, mouse, and touch events natively. Emits position as a percentage of total container width.

Note: Style the handle with a visible grip indicator (4px wide inner bar, changes colour on hover). Without a clear affordance, users don't discover the split is adjustable.

Panel size persistence

Data

useLocalStorage hook from usehooks-ts stores the [leftPercent, rightPercent] array under a key like 'split-layout'. On mount, the stored value is passed to PanelGroup's defaultLayout prop so the user's last ratio is restored immediately without a flash.

Note: In Next.js, read localStorage in a useEffect rather than useState to avoid SSR hydration mismatches. Use dynamic import with ssr: false for the entire PanelGroup component if hydration errors persist.

Panel collapse controls

UI

ChevronLeft and ChevronRight icon buttons (from lucide-react) that call panelRef.current.collapse() and panelRef.current.expand() from the react-resizable-panels API. Toggling a panel hidden gives full-width focus to the active work area.

Note: The Panel component must have collapsible={true} and collapsedSize={0} set. Without collapsible=true, react-resizable-panels enforces minSize and snaps back instead of collapsing.

Content reflow notifier

UI

A ResizeObserver attached to each panel's DOM node. Fires a callback whenever the panel's pixel width changes during a drag. Inner components that don't respond to CSS alone — Recharts (needs parent re-render), Mapbox GL (needs map.resize()), and iframes — must hook into this callback to reflow their content.

Note: This is the most-missed component in AI-generated builds. A chart or map will appear frozen at its initial size while the panel moves around it.

Keyboard access

UI

PanelResizeHandle from react-resizable-panels responds to ArrowLeft and ArrowRight key events natively when focused. Add tabIndex={0} and aria-label='Resize panels' to the handle element. This satisfies WCAG 2.1 keyboard operability without custom code.

Note: Test with Tab navigation — the handle must be reachable via keyboard before the collapse buttons, not buried after them in the tab order.

Mobile breakpoint handler

UI

CSS media query hides the resize handle and switches the outer flex container from row to column at the 768px breakpoint. Tailwind pattern: flex-col on the PanelGroup, overridden to flex-row at md:. On mobile, each panel takes full width and scrolls independently as stacked blocks.

Note: Do not try to preserve the drag handle on mobile — a touch target this narrow is unusable on a phone screen. Stack and move on.

Build it — pick your path

Each tool fits this feature differently. Switch tabs to compare fit, time, the exact steps, and a copy-paste prompt.

Best UI, Next.js ecosystemFit for this feature:

V0's Next.js output is the cleanest path for split screen — strong TypeScript types for panel refs, Design Mode for adjusting initial ratio visually, and react-resizable-panels maps directly to idiomatic App Router code.

Step by step

  1. 1Paste the prompt below into V0 and specify the two panel contents
  2. 2In the V0 editor, use Design Mode to drag the initial split ratio to your preferred default before exporting
  3. 3Add your Supabase env vars in the Vars panel if the left or right panel content needs database data
  4. 4Publish to production and verify localStorage persistence by refreshing after dragging the handle
  5. 5Test on an iPhone or Android — confirm panels stack vertically at 768px
Paste into v0
Build a resizable split-screen layout for a Next.js App Router page using react-resizable-panels. Left panel: [describe left panel content]. Right panel: [describe right panel content]. Use PanelGroup with direction='horizontal' and a PanelResizeHandle between panels. Set minSize={20} on each Panel. Make the right panel collapsible with collapsible={true} and collapsedSize={0}; add collapse and expand buttons with ChevronLeft/ChevronRight icons from lucide-react that call the panel's ref methods. Persist the split layout array to localStorage under the key 'split-layout' with usehooks-ts useLocalStorage; restore the value via defaultLayout on PanelGroup; wrap the component in dynamic import with ssr: false to avoid SSR hydration mismatch. Attach a ResizeObserver to each panel container div and expose an onResize prop so parent components can notify inner charts or maps. On viewports below 768px, switch PanelGroup to direction='vertical' and hide PanelResizeHandle. Add aria-label='Resize panels' to PanelResizeHandle and tabIndex={0} for keyboard accessibility. Default layout: [50, 50].

Where this path bites

  • V0 occasionally generates a CSS-only implementation (percentage widths, no drag library) — explicitly name react-resizable-panels in the prompt to prevent this
  • V0 preview sandbox cannot accurately simulate touch events — test collapse and mobile layout on a deployed URL
  • Nested or multi-orientation splits (horizontal + vertical) significantly complicate the generated code and usually need manual cleanup

What it costs to run

Drag through the tiers to see how your monthly bill scales with users — no surprises later.

Estimated monthly running cost

$0/mo

Pure client-side component — react-resizable-panels is open-source, localStorage is free, no backend needed. Zero running cost.

Estimates use verified 2026 pricing and assume typical usage per user. Your real bill depends on activity, storage, and third-party plans.

What breaks when AI tools build this

The failures people actually hit on their first build — the symptom, why it happens, and the exact fix.

Chart or map stays frozen when panel is resized

Symptom: Recharts, Mapbox GL, Leaflet, and similar libraries measure their container on mount and do not automatically respond to subsequent CSS size changes. When the panel drag handle moves, the container's pixel width changes but the chart never finds out — it stays painted at its initial render width.

Fix: Attach a ResizeObserver to the panel container div. In the callback, trigger a re-render for Recharts (setState a width variable and pass it as the chart's width prop), or call map.resize() for Mapbox GL. Specify this in your prompt: 'attach a ResizeObserver to each panel container and call map.resize() / chart.resize() in the callback.'

Collapse button collapses then immediately snaps back

Symptom: Clicking the collapse button reduces the panel to zero width, but react-resizable-panels enforces its minSize and immediately snaps back to the minimum — so the panel appears to flicker rather than collapse cleanly.

Fix: Set both collapsible={true} and collapsedSize={0} on the Panel component. The collapsible flag tells react-resizable-panels to allow sizes below minSize during a programmatic collapse; without it, minSize wins every time.

Drag handle works on desktop but is not draggable on iOS Safari

Symptom: iOS Safari does not fire mouse events (mousedown, mousemove) on non-input elements, which is what older split libraries like split.js rely on. The handle appears but cannot be dragged on any iPhone regardless of iOS version.

Fix: Use react-resizable-panels, which implements drag handling with the Pointer Events API (pointerdown, pointermove, pointerup). This works uniformly across mouse, touch, and stylus without separate event paths.

Split ratio does not restore from localStorage after a page reload

Symptom: In Next.js, localStorage is only available in the browser. If the PanelGroup's defaultLayout reads localStorage during server rendering, it gets undefined, and Next.js hydrates with the server value — overwriting whatever was in storage before the component mounts.

Fix: Use dynamic import with ssr: false for the component containing PanelGroup, so it is never rendered on the server. Alternatively, read localStorage inside a useEffect and call panelGroupRef.current.setLayout() after mount, never in the initial render.

Best practices

1

Always use react-resizable-panels instead of CSS-only or split.js for new builds — Pointer Events support means it works on touch screens without extra code

2

Set a minimum panel size of 200px or 20% whichever is larger — panels that collapse to near-zero during a drag feel broken and confuse users

3

Persist the split ratio to localStorage on every onLayout callback, not just on drag end — this way a crash mid-drag still saves progress

4

Attach a ResizeObserver to every panel that contains a chart, map, editor, or iframe so inner content reflows automatically without manual triggers

5

Add collapse/expand buttons alongside the drag handle — many users never discover they can drag but would use a one-click collapse button if it were visible

6

Test the keyboard path: Tab to the resize handle, ArrowLeft/ArrowRight to move it, Enter to collapse — all three must work without a mouse

7

On narrow viewports, stack panels vertically and hide the drag handle entirely — a touch-unfriendly thin handle on a phone is worse than no split at all

When You Need Custom Development

AI tools cover the two-panel split-screen pattern reliably. Certain requirements outgrow what react-resizable-panels and a prompt can produce:

  • Four or more panels in a tree of mixed horizontal and vertical splits (VS Code / Figma layout) — requires a recursive panel tree component that AI tools cannot generate correctly
  • Panel layout presets saved per user in the database and synced across devices, with a preset picker UI
  • Individual panels are micro-frontends with independent routing, state, and even different tech stacks — requires custom message passing between panel iframes
  • Real-time synchronised scrolling or live diff highlighting between panels where every character change in one panel is mirrored in the other

RapidDev builds these features for production

Real auth, database, and payments — fixed price, delivered in weeks. You own 100% of the code.

Get a fixed-price quote

Frequently asked questions

Which library should I use for split screen in React?

react-resizable-panels is the current recommendation for new projects. It uses the Pointer Events API so it works on touch screens without extra configuration, ships with full TypeScript types, and exposes a ref-based API for programmatic collapse. The older react-split (split.js) works fine for desktop-only apps but requires polyfilling for iOS touch.

How do I persist the split ratio so it survives a page reload?

Use the useLocalStorage hook from usehooks-ts to store the layout array (e.g., [50, 50]) and pass the stored value to PanelGroup's defaultLayout prop. In Next.js, wrap the PanelGroup in a dynamic import with ssr: false to avoid the server reading undefined from localStorage during SSR.

Can panels collapse to zero width?

Yes, but you need to explicitly enable it. Set collapsible={true} and collapsedSize={0} on the Panel component. Without collapsible=true, react-resizable-panels enforces minSize and will snap the panel back open instead of collapsing it.

Does split screen work on mobile?

A two-panel side-by-side layout is too narrow to use on most phone screens. The standard approach is to stack panels vertically below the 768px breakpoint using a CSS media query and hide the resize handle entirely. Users get a normal single-column experience on mobile.

How do I make a chart resize when its panel is resized?

Recharts, Mapbox GL, and similar libraries do not respond to CSS size changes automatically. Attach a ResizeObserver to the panel container div. In the observer callback, update a width state variable (which Recharts reads) or call map.resize() directly for Mapbox GL or Leaflet. Include this in your initial prompt to avoid a second iteration.

Can I have more than two panels?

Yes — react-resizable-panels supports multiple panels in a single PanelGroup, and you can nest PanelGroups with mixed directions for grid-style layouts. That said, two-panel splits cover 95% of real use cases. Four-panel grids require a recursive component that is significantly harder to build and maintain.

How do keyboard users resize the panels?

PanelResizeHandle from react-resizable-panels handles keyboard interaction natively — focus the handle with Tab and use ArrowLeft/ArrowRight to nudge it. Add aria-label='Resize panels' to the handle element to communicate its purpose to screen reader users.

Can I sync the split layout across devices?

Yes, but it adds backend complexity. Store the layout array in a Supabase user_preferences table and fetch it on sign-in. The cross-device sync costs $0–25/mo on Supabase depending on your total usage. For most apps, localStorage-only persistence is the right default — only add database sync if users explicitly request it.

RapidDev

Need this feature production-ready?

RapidDev builds split screen into real apps — auth, database, payments — at $13K–$25K.

Book a free consultation

30-min call. No commitment.

Want this built for you?

We ship production apps at a fixed price — $13K–$25K, 6–10 weeks, source code yours. You've seen what it takes; we do it every week.

Get a fixed-price quote

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.