Skip to content

PATTERN Cited by 1 source

Flex on top of native UI framework

Problem

You want Flex layout semantics on mobile — so a single Flex specification (authored on a server, or in a cross- platform codebase) renders consistently on iOS + Android — but you do not want to lose access to:

  • Native platform UI performance (UICollectionView recycling, RecyclerView view recycling, hardware-accelerated scroll).
  • New OS-version APIs that the platform team ships per-year (iOS 17 / 18 APIs, Android 14 / 15 APIs).
  • Platform-native gesture handling, accessibility services, text rendering, and animation systems.

Naïvely, two options look attractive:

  • Pure-web WebView — loses all three. Native feel gone.
  • Cross-platform layout engine that replaces the native UI system (like older Flutter pre-impeller, or some game-engine-based UI toolkits). Can't take advantage of new OS APIs easily; platform-native behaviours need to be reimplemented.

Pattern

Choose a layout library that sits on top of the native UI framework — "to assist with positioning and sizing, without replacing or altering the behaviour of the native UI framework" — and translate your Flex spec into that library's node tree. The library then produces standard native UI objects (UICollectionView / UITableView on iOS; RecyclerView / View on Android).

Appcraft's implementation, verbatim:

"One important consideration while choosing the library was finding one that sits on top of the native UI frameworks to assist with positioning and sizing, without replacing or altering the behaviour of the native UI framework. This means that, for example, a scrollable layout with Flex specifications on the server will be transformed by Appcraft into a native UICollectionView for iOS and into a RecyclerView for Android. This approach ensures that we still have access to new APIs and improvements available on the native UI frameworks for newer OS versions."

(Source: sources/2024-05-15-zalando-transitioning-to-appcraft-evolution-of-zalandos-server-driven-ui-framework.)

Concrete implementation (Appcraft)

  • iOS: Texture (AsyncDisplayKit). A Flex library on top of Texture translates the Flex spec into a Texture node tree which in turn produces UICollectionView + UIKit objects.
  • Android: Litho. Internally uses Meta's Yoga C++ Flex engine; produces RecyclerView + Android View objects.

Both libraries share a crucial property: they compute layout asynchronously, off the main thread, which is how they maintain scroll smoothness. They were selected partly for that property and partly for their "on top of, not in place of" stance.

Structural benefits

  1. OS-version API access preserved — new iOS/Android platform features are accessible because the objects in the final tree are still native platform objects. You don't have to wait for the cross-platform layer to catch up.
  2. Native behaviour preserved — gestures, accessibility (VoiceOver, TalkBack), text scaling, RTL layout, dark mode — all work because the final view objects are OS-native.
  3. Cross-platform parity — the Flex spec is the shared contract; each platform's Flex library is responsible for faithfully honouring it.
  4. Incremental adoption — existing native screens can coexist with Flex-laid-out ones; you don't have to rewrite the app.

Implementation concerns

Library selection

The two libraries (Texture + Litho, at Zalando's choice) must be:

  • On top of, not instead of, the native UI framework.
  • Well-maintained (both Texture and Litho are open-source with active community use).
  • Have predictable Flex-spec → platform-view translation semantics.

Parity effort

The Appcraft team noted that "most of the effort went into translating the Flex definitions from the server into the Flex library APIs for each platform and comparing them to ensure consistent results between both." Cross-platform Flex parity is earned, not given; it needs test coverage and visual regression checks.

Library-drift risk

The Appcraft post names third-party library drift as an ongoing open challenge: "iOS and Android libraries may behave differently, requiring additional customization or default code to achieve consistent functionality and user experience across both platforms." The layering-on-top-of-native choice trades full control for OS-API-access; it does not eliminate the library-parity problem.

Not a full layout language

Flex can't do everything CSS Grid can. Screens that need grid layouts need additional primitives or workarounds (nested Flex, explicit size calculations). This is a feature trade, not a bug — the narrower the layout language, the easier the cross-platform parity.

Contrast with other mobile cross-platform approaches

Approach Native objects? OS-API access Example
Flex on top of native Yes Yes Appcraft (Texture+Litho)
React Native Yes (via Yoga + RN primitives) Yes via escape hatches RN itself
Flutter (pre-Impeller) No (custom compositor) Limited Flutter
Web in WebView No Very limited Older Zalando pages
Cross-compiled UI toolkit Varies Varies Qt, Xamarin.Forms

This pattern is closest in shape to React Native but at a different altitude: RN is a full app framework; Flex-on-top- of-native is just the layout/rendering substrate, agnostic about whether the authoring is done in React, Swift, Kotlin, or server-emitted JSON.

Anti-patterns

  • Re-implement the native UI system in your layout library — you lose all OS API evolution.
  • Flex library that mutates UIKit/View internals — even "on-top-of" libraries can break if they reach into private APIs. Choose libraries that respect the platform boundary.
  • Different Flex semantics on iOS vs Android — if the team let's per-platform quirks leak into the Flex contract, the cross-platform parity benefit evaporates.

Seen in

Last updated · 550 distilled / 1,221 read