How layouts respond to changing window sizes instead of breaking on every multitasking mode
An iPad screen has long stopped being a guaranteed, fixed full screen space for an app, and can shrink to a fraction of its original width at any moment through Split View, Slide Over or Stage Manager, without the app ever restarting. Anyone who bakes fixed pixel widths or an assumed screen orientation into their components will eventually see clipped content or overlapping elements. This article covers how React Native apps respond to these window size changes, which responsive layout strategies replace fixed full screen assumptions, and how to practically test the different multitasking states.
Table of Contents
- 1. Overview of iPadOS multitasking modes
- 2. How an app learns about window size changes
- 3. Identifying fixed full screen assumptions in existing code
- 4. Responsive layout strategies instead of fixed full screen assumptions
- 5. Safe area behavior alongside multitasking
- 6. Info.plist configuration for multitasking support
- 7. Stage Manager: freely resizable windows as a further step
- 8. Testing approach for different multitasking states
- 9. Practical example: an adaptive grid layout for a product list
- 10. Summary
- 11. FAQ
1. Overview of iPadOS multitasking modes
iPadOS has several distinct multitasking states that fundamentally differ for an app: in the classic full screen mode, the app takes up the entire available screen area, while Split View divides the screen between two apps, allowing window widths ranging from roughly a third up to half the screen depending on the chosen split. Slide Over places a third app as a floating, smaller window on top of the other two, which suddenly renders an app in a noticeably narrower, vertically oriented window, regardless of the iPad's actual physical orientation.
Stage Manager, available on newer iPad models, further extends this concept with freely resizable, overlapping windows whose size the user can change at will by dragging a window's corner, similar to a desktop operating system. For a React Native app, this whole catalog of modes means the available screen area at runtime can never be treated as a fixed constant, but as a value that can change at any moment while the app is already running.
2. How an app learns about window size changes
The useWindowDimensions hook from React Native core returns the current width and height of the window available to the app and automatically triggers a re-render of the calling component whenever those values change, for example because the user drags the divider between two apps in Split View. Unlike the static Dimensions.get('window') API, which only returns the value once at the time it is called, useWindowDimensions continuously reacts to every change, making it the preferred choice for any component whose layout depends on the actual window size.
For cases where a window size change needs handling outside the React render cycle, such as triggering a native animation, the Dimensions API additionally provides an addEventListener for the change event, letting the same change be handled imperatively as well. In most cases, though, the declarative useWindowDimensions hook is fully sufficient, since React already handles re-renders on state changes anyway.
import { useWindowDimensions, View } from 'react-native';
function ProductLayout() {
const { width } = useWindowDimensions();
const isCompact = width < 600;
return (
<View style={{ flexDirection: isCompact ? 'column' : 'row' }}>
<ProductList compact={isCompact} />
<ProductDetail visible={!isCompact} />
</View>
);
}
3. Identifying fixed full screen assumptions in existing code
The most reliable way to spot hidden full screen assumptions in an existing codebase is a targeted search for Dimensions.get('window') as well as hardcoded pixel values in style definitions that clearly assume the full iPad width, such as width: 1024 or a fixed column count in a grid that ignores the possibility of being shrunk. Layouts that read the window width once at component mount time and store the result in local state without reacting to later changes are particularly commonly affected.
A second, less obvious source of bugs lies in conditions that determine tablet specific behavior purely based on the device itself rather than on the actually available window width, such as a check like Platform.isPad, which still returns true even while the app runs in a narrow Slide Over window. For reliable behavior, the actual width through useWindowDimensions, not the device class itself, should drive layout decisions.
4. Responsive layout strategies instead of fixed full screen assumptions
Instead of using fixed pixel values in style objects, a layout should consistently build on flexbox properties such as flex, flexWrap and minWidth, which behave proportionally regardless of the actually available width and therefore automatically grow or shrink with the window. For structural decisions that cannot be solved purely through flexbox, such as whether a two column view even makes sense or should switch to a single column display, clearly defined breakpoints that react to the same value returned by useWindowDimensions work well.
A central useBreakpoint hook has proven useful in practice, translating the current window width into named categories such as compact, regular and expanded, similar to the size class concept from UIKit, instead of defining separate, possibly inconsistent width thresholds inside every individual component. This shared hook ensures every component in the app aligns with the same thresholds and shows consistent rather than fragmented layout behavior when switching between Split View and full screen.
import { useWindowDimensions } from 'react-native';
type Breakpoint = 'compact' | 'regular' | 'expanded';
function useBreakpoint(): Breakpoint {
const { width } = useWindowDimensions();
if (width < 600) return 'compact';
if (width < 900) return 'regular';
return 'expanded';
}
function CatalogScreen() {
const breakpoint = useBreakpoint();
const columns = breakpoint === 'compact' ? 1 : breakpoint === 'regular' ? 2 : 3;
return <ProductGrid columns={columns} />;
}
5. Safe area behavior alongside multitasking
react-native-safe-area-context returns the current safe area insets, meaning the distance to the notch, the home indicator and rounded corners, and those values can differ between Split View or Slide Over mode and full screen mode, because the app's area shifts relative position within the physical screen. An app sitting in Slide Over as a narrow, centered window over another app, for instance, has different effective margins than the same app running full screen, even though the physical device stays identical.
SafeAreaProvider from react-native-safe-area-context automatically reacts to these changes and updates the values returned through useSafeAreaInsets whenever the multitasking state changes, so a component that reads its insets correctly through the hook rather than through assumed fixed values stays automatically correct in every multitasking state, without needing any extra code to detect which mode is currently active.
6. Info.plist configuration for multitasking support
For an iPad app to support Split View and Slide Over at all, the UIRequiresFullScreen key in Info.plist must either be absent or explicitly set to false, because its absence in older, template generated projects can still default to true in some cases and permanently excludes the app from the multitasking pool. Every supported interface orientation for both iPhone and iPad must also be correctly declared under UISupportedInterfaceOrientations~ipad, since multitasking windows on iPad can appear in either axis regardless of the device's physical orientation.
For Expo projects, this configuration can be controlled directly through the ios.requireFullScreen key in app.json without manually editing the native Info.plist, where the value deliberately needs to be set to false, since Expo enables a more conservative full screen mode by default in newly generated projects, one that effectively disables multitasking even if the rest of the code is already fully built responsively.
{
"expo": {
"ios": {
"requireFullScreen": false,
"supportsTablet": true
}
}
}
7. Stage Manager: freely resizable windows as a further step
Stage Manager extends the classic Split View and Slide Over modes with windows that can be freely resized by dragging, no longer limited to a handful of fixed ratios but able to vary continuously between a minimum and the full screen width. For a React Native app, that means breakpoints should not be thought of as a rigid, small set of fixed steps, but the layout must keep looking sensible even at unusual intermediate widths, such as 740 instead of one of the classic Split View values.
In practice this mainly means treating breakpoint boundaries as ranges rather than exact expected values, and checking every layout for consistency independent of the exact pixel count, instead of relying on a small, fixed list of known iPad resolutions that Stage Manager has already made incomplete anyway. A layout that only looks correct at exactly 768 or 1024 pixels wide but breaks at 850 pixels is no longer a robust solution in a Stage Manager world.
8. Testing approach for different multitasking states
The iOS Simulator in Xcode supports Split View and Slide Over directly through the Simulator menu bar, or by manually dragging a second simulated app to the edge of the screen, letting the most important multitasking transitions be tested during development without a physical device. For systematic coverage, a small checklist pays off, covering at minimum the full screen state, the one third and two thirds Split View splits, and Slide Over on both possible sides of the screen.
On top of manual checking, an automated test can be written with Detox or Maestro that renders the app at several simulated window widths and checks through snapshot comparisons whether key layout elements such as navigation bars or action buttons get clipped or overlap at any of the tested widths. These automated checks do not replace real observation on a physical iPad, but reliably prevent a later code change from silently breaking a width that used to work correctly.
9. Practical example: an adaptive grid layout for a product list
A product list view showing three or four columns in full screen mode on a large iPad needs to reduce to two columns in Split View at half screen width and switch to a single column in Slide Over or a very narrow Stage Manager window width, so individual product cards do not get squeezed below a sensible minimum width. The column count should not be derived from a fixed window size table but directly from the available width divided by a defined minimum width per card, so unusual intermediate widths under Stage Manager still produce a clean result.
In practice, a simple formula such as Math.max(1, Math.floor(width / 280)) for a minimum card width of 280 pixels gives a more robust result than a list of fixed breakpoints, because it continuously adapts to any window width instead of visibly jumping or looking wrong at certain intermediate values nobody planned for.
import { useWindowDimensions, FlatList } from 'react-native';
const MIN_CARD_WIDTH = 280;
function ProductGrid({ products }: { products: Product[] }) {
const { width } = useWindowDimensions();
const columns = Math.max(1, Math.floor(width / MIN_CARD_WIDTH));
return (
<FlatList
key={columns} // forces a rebuild when the column count changes
data={products}
numColumns={columns}
renderItem={({ item }) => <ProductCard product={item} />}
/>
);
}
| Multitasking mode | Typical window width | Distinguishing feature | Layout consequence |
|---|---|---|---|
| Full screen | Full iPad screen width | Default starting state | Multi column layout possible |
| Split View (1/2) | Roughly half the screen width | Two apps visible side by side | Reduced column count, more compact spacing |
| Split View (1/3) | Roughly a third of the screen width | Narrowest Split View step | Single column layout often required |
| Slide Over | Narrow, floating window | Vertically shaped regardless of device orientation | Fully responsive, single column layout |
| Stage Manager | Freely resizable between minimum and full screen | Continuous rather than stepped widths | Formula based instead of fixed breakpoints needed |
Mironsoft
React Native app development and Magento integration
A mobile app for the Magento shop that actually runs smoothly?
We build React Native apps cleanly connected to the Magento REST or GraphQL API, from the first line of code to publishing on the App Store and Google Play.
App Concept
Plan the architecture and feature scope of a Magento-connected app together.
Magento API Integration
Cleanly connect product catalog, cart, and checkout to the shop API.
Store Publishing
Guide the App Store and Google Play release process without pitfalls.
10. Summary
iPad Split View and Multitasking: Key Takeaways
Detection
useWindowDimensions returns the current window width and automatically triggers a re-render on every change.
Strategy
Flexbox instead of fixed pixel values, paired with clearly defined breakpoints for structural layout decisions.
Configuration
UIRequiresFullScreen, or ios.requireFullScreen, must be set to false for multitasking to work at all.
Stage Manager
Freely resizable windows require formula based rather than rigidly stepped layout decisions.