Most teams build the same screen three times: once for iPhone, once for Android, once for the browser. That triples the work and the bugs. This guide shows you a cheaper path: design one language, build it once, ship a consistent v1, then add native polish only where it pays off.

A capsule wardrobe of a few coordinated garments that combine many ways. No em-dashes.
A capsule wardrobe is a few coordinated pieces that mix into many outfits: one design system serves iOS, Android, and web the same way.

The core idea: design once, adapt later

A “design language” is your fixed set of colors, typography, spacing, and components. When you keep that language identical across platforms, your app looks like one product everywhere. Users learn it once. You maintain it once.

The temptation is to chase native perfection from day one: iOS feels one way, Android another, web a third. That path is expensive, slow, and easy to get wrong before you know what users actually need.

Instead, follow a “design ladder”. Start unified. Climb to platform-native polish later, and only where it earns its cost.

Step 1One mockupDesign a single screen in one design language for all three platforms.
Step 2Build onceUse React Native with Expo so all three platforms share design and code.
Step 3Ship v1Release a consistent first version. Watch how real users behave.
Step 4Adapt nativelyAdd iOS, Android, and web specifics where they measurably help.

Step 1: Start with one mockup

Open Figma and design a single screen. Pick one set of colors, one type scale, one spacing rhythm, and one set of components. Do not make iOS, Android, and web versions yet. Make one version that you would accept on all three.

This forces a clear decision: what is the product, before what is the platform? A consistency-first mockup is faster to draw, faster to review, and faster to change. You ship a v1 with one source of truth instead of three drifting designs.

For the design-first workflow that turns this mockup into a clickable prototype, follow the mockup-to-prototype guide . For layout decisions inside the screen, use the white-space and visual hierarchy guide .

Why consistency-first is cheaper for a v1

  • One review loop: Stakeholders approve one design, not three.
  • One bug surface: A spacing fix lands everywhere at once.
  • One mental model: Your team and your users learn a single system.
  • Faster learning: You reach real users sooner, so you learn what to improve.

You can always add native detail later. You cannot get back the weeks spent perfecting three versions of a screen nobody validated.

Step 2: Build it once with React Native and Expo

React Native is a framework that lets you write one codebase that runs as a real iOS app, a real Android app, and a web app. Expo is a toolkit on top of React Native that handles building, testing, and shipping so you do not configure native projects by hand.

Together they let your three platforms share both the design AND the code. One component definition renders on all three. Read what React Native is and the Expo overview for the fundamentals.

Here is how the layers stack up when you build this way.

Design language
ColorsType scaleSpacingone source of truth in Figma
Components
ButtonCardInputwritten once in React Native
Platform layer
Platform.select()small per-platform overrides only
Targets
iOSAndroidWebone codebase, three outputs

One component that adapts per platform

When you do need a small difference, React Native gives you Platform.select(). It picks a value based on the device the code runs on. The component stays shared. Only the chosen value changes.

The example below is one button. The design (color, padding, label) stays identical. Only the shadow style differs, because iOS and Android render shadows differently and web uses a CSS box shadow.

tsx
import { Platform, Pressable, Text, StyleSheet } from 'react-native';

export function PrimaryButton({ label, onPress }) {
  return (
    <Pressable style={styles.button} onPress={onPress}>
      <Text style={styles.label}>{label}</Text>
    </Pressable>
  );
}

const styles = StyleSheet.create({
  button: {
    backgroundColor: '#e0314b',
    paddingVertical: 14,
    paddingHorizontal: 24,
    borderRadius: 12,
    // Shared design stays the same. Only the shadow adapts per platform.
    ...Platform.select({
      ios: {
        shadowColor: '#000',
        shadowOpacity: 0.2,
        shadowRadius: 6,
        shadowOffset: { width: 0, height: 2 },
      },
      android: {
        elevation: 4,
      },
      web: {
        boxShadow: '0 2px 6px rgba(0,0,0,0.2)',
      },
    }),
  },
  label: {
    color: '#ffffff',
    fontSize: 16,
    fontWeight: '600',
    textAlign: 'center',
  },
});

Notice what stays shared: the brand red, the padding, the radius, the label. The platform difference is a few lines, contained in one place. That is the whole pattern. See the React Native platform-specific code docs for the full API.

Step 3: Ship a consistent v1

Release the unified version to all three platforms at once. Resist the urge to polish per platform before launch. Your goal is to put a coherent product in front of real users quickly.

A consistent v1 still feels professional. Users do not reject an app because its shadow matches across platforms. They reject it because it is slow, confusing, or unfinished. Consistency buys you focus on the things that actually matter for a first release.

Step 4: Climb the design ladder to native polish

Once real usage tells you where friction lives, adapt. This is the top of the ladder: deliberate, measured, platform-native detail.

Native adaptation means matching each platform’s conventions. iOS follows the Apple Human Interface Guidelines . Android follows Material Design 3 . Web follows browser and pointer conventions. Each has its own navigation, gestures, and controls.

Do not try to learn all three at once here. The deep, platform-by-platform specifics live in the platform-native UX patterns guide . For choosing menus and navigation structure per platform, use the mobile navigation patterns guide .

What to adapt first

  • Navigation: A bottom tab bar on iOS, a navigation drawer or bottom bar on Android, a top nav on wide web.
  • Back behavior: Android has a hardware or gesture back. iOS uses a back button. Web uses browser history.
  • Controls: Date pickers, switches, and menus that match each platform’s native widget.
  • Typography defaults: The system font on each platform if you choose to use it.

Adapt one thing at a time. Measure whether it helps. Keep the shared design language as your baseline so the product never fragments.

Unified vs platform-native: when to invest

Use this table to decide where you are on the ladder.

Unified designPlatform-native adaptation
Stagev1 and early growthAfter real usage data
CostLow, one buildHigher, per-platform work
Best forBrand consistency, speedFriction points, retention
Risk if skippedLooks slightly genericFeels foreign on a platform
EffortOne screen, three outputsOne platform at a time
Invest whenAlways, as your baselineA platform metric demands it

The rule is simple. Unified is your default. Native polish is an upgrade you buy with evidence, not a starting requirement.

A quick checklist

  • Design one mockup in one design language for all three platforms.
  • Build it once with React Native and Expo so design and code are shared.
  • Keep platform differences small and contained with Platform.select().
  • Ship a consistent v1 and watch real users.
  • Climb to native polish only where data shows it helps.

Follow this ladder and you spend your effort where it counts: a coherent product first, native refinement second.

Further reading