Can CeylanVienna-based, globally curious.
Learn/Frontend

Building a web app for future native migration: constraints from day one

If you're planning to wrap your web app in a native shell later, the constraints aren't optional from day one. Web-only APIs baked into your components will block the migration.

2026-04-18·3 min read·intermediate

The migration that breaks halfway through

You build a web app. It works well. You decide to ship it as a mobile app using a framework that wraps web apps in a native shell. You run the converter and hit a wall:

  • window.print() calls that crash on mobile
  • onMouseEnter handlers that have no touch equivalent
  • Fixed-width layouts that overflow at 375px
  • CSS hover states with no fallback for touch
  • navigator.clipboard calls that require browser permissions your shell doesn't grant

None of these are edge cases. They're standard web APIs that don't translate to native. If they're spread through your codebase, the migration is a rewrite, not a wrap.

The constraint list that prevents this

If native migration is a possibility, treat these as hard constraints from the first line of code:

Touch targets: every interactive element must be at least 44×44px. This is Apple's HIG requirement and Android's material spec. A 24px icon button that works fine with a cursor is unfixable with CSS alone on mobile.

No web-only events: onMouseEnter, onMouseLeave, onMouseOver have no touch equivalent. Use onClick and manage state explicitly. A dropdown that opens on hover needs a tap-to-open version on mobile anyway — build that version first.

No web-only APIs: window.print(), document.execCommand(), browser-specific clipboard APIs, and anything under window.location that assumes browser navigation. Replace with platform-agnostic equivalents before they proliferate.

Relative URLs everywhere: never hardcode http://localhost:3000 or a production URL in component code. Use relative paths (/api/...) or a config constant. Native shells proxy API calls differently.

375px as the design baseline: test at 375px (iPhone SE viewport) before considering any layout done. Nothing should overflow horizontally. Scroll should be intentional, not accidental.

Mobile-first CSS in practice

Write your base styles for small screens. Scale up with sm:, md:, lg: breakpoints:

/* Base: mobile */
.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

/* Tablet and above */
@media (min-width: 640px) {
  .grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

This is the opposite of how many desktop-first apps are built (wide layout first, media queries shrink it down). Mobile-first means the mobile layout is the default, and you progressively enhance upward.

What the native shell can and can't do

Native shell frameworks (Capacitor, Cordova, React Native WebView) give your web app:

  • Access to native device APIs (camera, push notifications, biometrics)
  • App store distribution
  • Offline capability with service workers

They do not fix:

  • Web APIs that have no native equivalent
  • Layout that doesn't work at mobile viewports
  • Performance issues from heavy JavaScript rendering

The shell is a packaging tool, not a compatibility layer. Your web app needs to already work on mobile before the shell adds value.

The real cost of retrofitting

Mobile-first constraints feel like overhead when you're building for desktop first. The actual overhead is minimal — it's mostly about discipline in which APIs you use and which breakpoint you design from first.

The cost of retrofitting is much higher. Going through an existing codebase to replace mouse events, fix viewport overflows, and remove web-only APIs is tedious, error-prone work. Building it correctly once costs less.

More like this, straight to your inbox.

I write about Frontend and a handful of other things I actually care about. No schedule, no filler — just when I have something worth saying.

More on Frontend

The no-build frontend: when you don't need React

Most internal tools and personal dashboards don't need a JavaScript framework. Here's the case for plain HTML and when the complexity earns its keep.

If this raised a question, I'd be happy to talk about it.

Find me →
← Back to Learn