CONCEPT Cited by 1 source
Cross-platform UI subset tradeoff¶
Any cross-platform UI abstraction — regardless of which substrate it picks (HTML, React Native primitives, Flutter widgets, SwiftUI, etc.) — has the same foundational constraint: it can only guarantee parity across targets for the intersection of what all target platforms natively support. Anything outside that intersection has to drop to a per-platform escape hatch.
The constraint¶
Given N target platforms (iOS, Android, web, desktop, wearables, TV), the cross-platform surface is:
Adding a target platform can only shrink or preserve the intersection — it cannot grow it. A capability that works beautifully on iOS but has no equivalent on web is not part of the cross-platform surface.
Practical consequences:
- The library you build on forces the subset. Choose carefully — the substrate is the ceiling.
- Anything you want to ship that exceeds the subset requires escape hatches, and the quality of the escape hatch is as important as the substrate itself.
- "100% cross-platform code share" is not a goal — it's actively infeasible for most non-trivial apps.
Zalando's framing¶
Zalando's 2025-10 post states the principle explicitly:
"Writing cross-platform code is a balancing act between saving development time and limiting yourself to cross-platform constraints. It's important to accept that having 100% code shared between all platforms or even between iOS and Android, is not the goal, just like writing everything in JavaScript and avoiding native code is not the goal, and that's totally fine."
This is an independent restatement of the same principle Shopify canonicalised in 2025-01 in sources/2025-01-13-shopify-five-years-of-react-native-at-shopify ("Think native and React Native, not native or React Native" — see patterns/mixed-native-plus-cross-platform-mobile-stack). Two companies at different points in their RN maturity, different architectural starting points, converging on the same rule.
Escape hatches¶
A cross-platform substrate is only as good as its escape hatches. Common shapes:
- Build-time file resolution:
Foo.ios.ts,Foo.android.ts,Foo.native.ts,Foo.ts. Enabled by Metro for RN — see concepts/platform-specific-import-resolution and patterns/platform-specific-ts-file-resolution. - Compat / passthrough APIs:
react-strict-dom's
compat.nativelets a developer inject platform-specific props and control the mapped native component directly. See patterns/compat-native-escape-hatch. - Runtime platform branching:
if (Platform.OS === 'ios')(RN). Works but ships all platform code to every platform. - Native modules: drop to Swift/Kotlin/C++ when the JS substrate can't reach the underlying platform capability. Canonicalised by patterns/mixed-native-plus-cross-platform-mobile-stack.
The health check¶
A cross-platform UI system is healthy when:
- The intersection subset is broad enough to handle most of the app's UI surface with no per-platform code.
- The escape hatches are clean and obvious when they're needed — no ambiguity about whether to eject.
- The team's culture accepts the non-intersection cost (some code will be per-platform, some investment in cross-platform UI will be redundant).
When any of those is missing, teams ship cross-platform code that works on one platform and is silently broken on another, or they reject cross-platform altogether.
Seen in¶
- sources/2025-10-02-zalando-accelerating-mobile-app-development-with-rendering-engine-and-react-native — Zalando's explicit statement of the principle, applied to the react-strict-dom + StyleX + Metro-file-resolution stack. Zalando is choosing an HTML-subset substrate; the principle generalises to any substrate choice.
- sources/2025-01-13-shopify-five-years-of-react-native-at-shopify — Shopify's independent restatement of the same rule at the whole-app-framework altitude.