# React Native on iPhone Duo: what breaks and what works
> Meta has shipped no iPhone Duo support. Which React Native patterns break on the foldable display, which survive, and where a native module becomes unavoidable.
Source: https://iphoneduosupport.com/blog/react-native-iphone-duo/
Published: 2026-09-09
Framework: react-native
Status: ENGINEERING ANALYSIS — this framework vendor has published no iPhone Duo guidance. Apple-side facts are sourced; framework-side conclusions are inference.
Sources: https://developer.apple.com/videos/play/tech-talks/111461/ https://developer.apple.com/videos/play/tech-talks/111463/ https://developer.apple.com/videos/play/tech-talks/111464/
Last verified: 2026-09-09
---
Meta has not shipped iPhone Duo support and has published no guidance for it. Everything below is our analysis of how React Native behaves against the APIs and behaviours Apple documented on 9 September 2026. The Apple-side facts are sourced; the React Native conclusions are reasoned inference you should verify against your own build.
The short version: React Native apps will mostly *work*, because flexbox is inherently adaptive. Three specific patterns break, and one capability is out of reach without native code.
## Why the baseline is better than you would expect
Under the hood, a React Native view hierarchy is a native view hierarchy. When iPhone Duo unfolds, UIKit resizes the root view, and Yoga relayouts everything inside it. An app built with flex ratios rather than fixed pixel values adapts without a single line of change.
That is genuinely most apps. Which makes the failures worth knowing precisely, because they are narrow.
## Break one: cached dimensions
This is the big one, and it is nearly universal.
```jsx
// Broken on iPhone Duo — evaluated once, at module load
const { width } = Dimensions.get('window');
const styles = StyleSheet.create({
card: { width: width - 32 },
});
```
That width was captured at launch. On iPhone Duo it becomes wrong when the user unfolds the device, folds it closed, rotates it, or resizes Split View. The style object is created once and never recomputed, so the card keeps its launch-time width forever.
The fix is the hook, which re-renders on change:
```jsx
function Card({ children }) {
const { width } = useWindowDimensions();
return {children};
}
```
Worth searching for specifically, since the module-scope form is invisible in review:
```bash
grep -rn "Dimensions.get" src/
```
Every hit outside a component render is suspect. Note that `Dimensions.addEventListener` is a partial fix at best — it fires, but a `StyleSheet.create` object built at module load will not be rebuilt by it.
There is a subtler variant worth checking: percentage-of-screen constants like `const CARD = width * 0.45`. These read as responsive and are not.
## Break two: orientation locking
Many React Native apps lock to portrait, in `Info.plist` or through a library. Apple states the inner display **does not honor supported interface orientations**.
So the lock silently stops working, and your app is laid out in configurations it was never designed for. If your layout assumed width is always less than height, that assumption is gone.
The replacement is not another lock. It is a layout that works at any aspect ratio:
```jsx
const { width, height } = useWindowDimensions();
const isWide = width > 600;
return isWide ? : ;
```
A width of 600 is a reasonable dividing line here: the inner display is 626 points wide and the outer is 466.
## Break three: collapsed safe area insets
`react-native-safe-area-context` reports the real insets. The problem is what application code does with them.
```jsx
// Common, and now wrong
const insets = useSafeAreaInsets();
```
Apple is explicit that safe areas are **asymmetric** on iPhone Duo. Taking the max, or applying one horizontal value to both edges, was harmless when the two matched. It now over-pads one side, and content drifts off-centre.
```jsx
```
`SafeAreaView` handles this correctly on its own. The bugs are in hand-rolled inset math.
## What you cannot reach
Here is the honest limitation. These have no JavaScript bindings today:
- `ReservedRegion` — where the hinge divides the display
- `ArrangementView` — pose-aware primary/secondary placement
- `onHingeChange` — hinge angle
- Scene accessories — content on the outer display while the app runs on the inner
- The vertical toolbar APIs — `axisBehavior`, `visibilityPriority`, and the rest
Reaching any of them means a native module wrapping the Swift API and bridging values into JS. For reserved regions that is a moderate piece of work: a native view that queries `reservedRegions(kind:)`, observes changes, and emits frames as props.
**Until someone ships that, a React Native app can be correct on iPhone Duo but not hinge-aware.** It can lay out properly at any size; it cannot avoid placing a button on the fold.
For most content apps — feeds, commerce, messaging, media — correctness is the whole job, and the fold falls in a place users tolerate. For a canvas, an editor, a drawing app, or a game board, the fold matters and you should budget for native work.
## What you get for free that is worth using
The inner display is regular-width in both dimensions, with room for a sidebar. If your app has a tablet layout behind a breakpoint, it will now appear on a phone, and it is probably the right layout. Check that your breakpoint is driven by live dimensions rather than by a device-type check:
```jsx
// Wrong — Platform.isPad is false on iPhone Duo
const isTablet = Platform.OS === 'ios' && Platform.isPad;
// Right
const { width } = useWindowDimensions();
const isWide = width >= 600;
```
Any device-info library used to pick a layout has this same problem.
## Split View, and the freeze bug
All apps participate in side-by-side multitasking on iPhone Duo — there is no opt-in. Two things to check:
**Continuous resize.** Dragging the Split View divider changes your width continuously. `useWindowDimensions` handles it; cached values do not.
**AppState.** In Split View your app can be visible but not active. Code that stops video, timers, or animation on `AppState` changing to `inactive` will look frozen to a user who can still see the window. This pattern is common in React Native for battery reasons, and it is worth revisiting for this device specifically.
## A pragmatic migration
1. `grep -rn "Dimensions.get"` — replace every module-scope call with `useWindowDimensions`
2. Remove orientation locks and fix whatever they were hiding
3. Audit `useSafeAreaInsets` consumers for symmetric math
4. Replace device-type layout checks with width checks
5. Test the Split View divider through its full range
6. Verify `AppState` handling does not freeze visible content
7. Decide whether the fold matters enough for a native module
Steps 1 to 4 are a day's work in most codebases and account for nearly all of the visible improvement.
## What would change this analysis
If React Native ships a `useDisplayFeatures`-style API bridging Apple's reserved regions, the last section becomes obsolete and hinge-aware layout becomes reachable in JS. Nothing has been announced. We will update this post if that changes — it is dated and versioned above.
---
Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc.