Back to blog

Ionic & Capacitor: How Web Tech Becomes Mobile Apps

ioniccapacitormobilecross-platformwebview
Ionic & Capacitor: How Web Tech Becomes Mobile Apps

Series: Cross-Platform Mobile Development
Next: React Native: How JavaScript Renders Native UIs


Ionic's pitch is simple: you already know how to build mobile apps. If you can build a website, you can build a mobile app. No new language, no new paradigm — your HTML, CSS, and JavaScript run inside a native app shell.

This sounds too good to be true. And for years, critics dismissed it as "just a WebView wrapper." But understanding how Ionic and Capacitor actually work reveals why this approach is not only valid — it's the best choice for a surprising number of apps.

A Brief History: From PhoneGap to Capacitor

The idea of running web code on mobile devices isn't new:

The Cordova Era (2011-2019)

Apache Cordova (originally PhoneGap) was the pioneer. It embedded a WebView in a native app and exposed native APIs through JavaScript plugins. Ionic built on top of Cordova, adding:

  • A beautiful UI component library (that mimicked native iOS/Android look)
  • Angular integration (later React and Vue too)
  • CLI tooling and build pipeline

But Cordova had serious problems:

  • Plugin ecosystem was fragile — plugins broke between platform updates
  • No first-class native project access — the native projects were build artifacts, not source code
  • Slow to adopt new platform features — always playing catch-up with iOS/Android
  • WebView quality varied wildly — especially on older Android devices

The Capacitor Revolution (2019-Present)

The Ionic team built Capacitor from scratch to replace Cordova. The key insight: treat native projects as source code, not build artifacts.

With Cordova, you never touched the Xcode or Android Studio projects directly — they were generated. With Capacitor, the ios/ and android/ folders are part of your repo. You can open them in Xcode/Android Studio, add native code, configure anything.

This single architectural decision solved most of Cordova's problems.

How It Actually Works

The WebView Architecture

At its core, an Ionic + Capacitor app is a native app that contains a WebView:

On iOS: The WebView is WKWebView — the same engine that powers Safari. It's fast, GPU-accelerated, and has access to the latest web APIs.

On Android: The WebView is based on Chromium (Chrome's engine). Since Android 7+, it auto-updates via the Play Store, so modern Android WebViews are excellent.

What Happens When Your App Launches

  1. Native app starts → loads the Capacitor runtime
  2. Capacitor creates a WebView → loads your index.html from local files (not a remote server)
  3. Your web app boots → React/Angular/Vue initializes, renders your UI
  4. Capacitor injects the bridgewindow.Capacitor becomes available in JavaScript
  5. App is ready → user interacts with your web UI inside the native shell

The Capacitor Bridge: Web ↔ Native Communication

When your web code needs to access native features (camera, GPS, push notifications), it goes through the Capacitor bridge:

// In your web code (JavaScript/TypeScript)
import { Camera, CameraResultType } from '@capacitor/camera';
 
// This call crosses the bridge to native code
const photo = await Camera.getPhoto({
  quality: 90,
  resultType: CameraResultType.Uri
});
 
// photo.webPath is now a local file URI you can display

What happens under the hood:

The bridge uses message passing — JavaScript sends a serialized message to native code, native code processes it asynchronously, then sends the result back. This is asynchronous by design, so it never blocks the UI thread.

Key Difference from Cordova's Bridge

Cordova's bridge used UIWebView (deprecated) on iOS and had a string-based plugin interface that was slow and fragile. Capacitor's bridge:

  • Uses modern WKWebView message handlers on iOS
  • Uses @JavascriptInterface annotation on Android
  • Has a typed plugin API — plugins define TypeScript interfaces
  • Supports synchronous calls for simple operations (via JSI-like direct access)

Capacitor Plugins: The Native API Layer

Capacitor's plugin system is how your web code accesses native functionality. There are three tiers:

1. Official Plugins (maintained by the Ionic team)

npm install @capacitor/camera
npm install @capacitor/geolocation
npm install @capacitor/filesystem
npm install @capacitor/push-notifications
npm install @capacitor/haptics
npm install @capacitor/share
npm install @capacitor/app
npm install @capacitor/keyboard

These cover the most common native APIs: camera, location, storage, notifications, biometrics, and more.

2. Community Plugins

The community maintains hundreds of plugins for less common needs — Bluetooth, NFC, in-app purchases, health data, etc.

3. Custom Plugins (Write Your Own)

If no plugin exists, you write native code directly:

// ios/App/App/MyPlugin.swift
import Capacitor
 
@objc(MyPlugin)
public class MyPlugin: CAPPlugin, CAPBridgedPlugin {
    public let identifier = "MyPlugin"
    public let jsName = "MyPlugin"
    public let pluginMethods: [CAPPluginMethod] = [
        CAPPluginMethod(name: "echo", returnType: CAPPluginReturnPromise)
    ]
 
    @objc func echo(_ call: CAPPluginCall) {
        let value = call.getString("value") ?? ""
        call.resolve(["value": value])
    }
}
// In your web code
import { registerPlugin } from '@capacitor/core';
 
const MyPlugin = registerPlugin('MyPlugin');
 
const result = await MyPlugin.echo({ value: 'Hello from web!' });
console.log(result.value); // "Hello from web!"

This is the power of Capacitor's "native projects as source code" approach — you can drop down to Swift/Kotlin whenever needed, without leaving the project.

The UI Layer: Ionic Framework Components

Ionic provides a component library that adapts to each platform:

import { IonButton, IonCard, IonInput, IonToggle } from '@ionic/react';
 
function MyForm() {
  return (
    <IonCard>
      <IonInput label="Email" type="email" />
      <IonToggle>Enable notifications</IonToggle>
      <IonButton expand="block">Submit</IonButton>
    </IonCard>
  );
}

Adaptive styling: The same <IonButton> renders with iOS styling on iPhone and Material Design styling on Android — automatically. No conditional code needed.

But here's what people miss: Ionic Framework is optional. Capacitor works with any web framework and any UI library. You can use:

  • Ionic + React (most common)
  • Ionic + Angular (the original pairing)
  • Ionic + Vue
  • Tailwind CSS + React (no Ionic components at all)
  • Any web framework — Capacitor doesn't care what renders in the WebView

Performance: The Real Story

"WebView apps are slow" is the oldest criticism. Let's break it down honestly:

Where WebView Apps Excel

  • UI rendering for standard interfaces — lists, forms, navigation, cards. Modern WebViews render these at 60fps. Users can't tell the difference from native.
  • Content-heavy apps — news readers, dashboards, admin panels. The web was literally designed for this.
  • Rapid iteration — hot reload, browser DevTools, instant preview. Development speed is unmatched.

Where WebView Apps Struggle

  • Complex animations — parallax effects, physics-based gestures, custom transitions. Possible but harder to hit 60fps consistently.
  • Heavy computation — image processing, ML inference, real-time audio. The WebView adds overhead compared to running directly on metal.
  • Platform-native interactions — drag-and-drop, custom keyboards, widget extensions. These require native code regardless of framework.

The 2026 Reality

Modern WKWebView (iOS) and Chromium WebView (Android) are dramatically faster than 5 years ago:

  • JIT compilation enabled on iOS WebView since iOS 14.5
  • GPU-accelerated rendering for CSS transforms, animations
  • WebAssembly for compute-heavy tasks
  • OffscreenCanvas for background rendering

For the majority of business applications, the performance difference between a WebView app and a native app is imperceptible to users.

When Ionic + Capacitor Is the Right Choice

Perfect Fit ✅

  • You have a web app and need a mobile version — wrap your existing React/Angular/Vue app, add Capacitor, ship to app stores
  • Internal enterprise apps — employee tools, inventory management, field service apps
  • Content and media apps — news, blogs, documentation, learning platforms
  • MVP / startup prototypes — ship fast, validate the idea, optimize later
  • Teams of web developers — no need to hire iOS/Android specialists
  • PWA + native in one codebase — deploy to web AND app stores from the same code

Think Twice ⚠️

  • Games or graphics-heavy apps — use Unity, Unreal, or Flutter instead
  • Apps that deeply integrate with OS features — home screen widgets, custom share extensions, Siri/Google Assistant shortcuts
  • Apps where "feels exactly native" is the top requirement — consider React Native or native
  • High-performance real-time apps — video editing, AR/VR, music production
  • Apps with heavy native UI customization — custom navigation controllers, native table view cells

Architecture Patterns for Production Ionic Apps

Shared Web + Mobile Codebase

The most powerful pattern: one codebase that deploys to web, iOS, and Android:

my-app/
├── src/
│   ├── components/     # Shared UI components
│   ├── pages/          # Shared pages/routes
│   ├── services/       # Business logic
│   ├── hooks/          # Shared React hooks
│   └── platform/       # Platform-specific code
│       ├── camera.ts       # Uses Capacitor on mobile, file input on web
│       └── notifications.ts # Push on mobile, Web Notifications API on web
├── ios/                # Native iOS project (Capacitor)
├── android/            # Native Android project (Capacitor)
├── public/
└── capacitor.config.ts
// src/platform/camera.ts
import { Capacitor } from '@capacitor/core';
import { Camera, CameraResultType } from '@capacitor/camera';
 
export async function takePhoto(): Promise<string> {
  if (Capacitor.isNativePlatform()) {
    // On mobile: use native camera
    const photo = await Camera.getPhoto({
      quality: 90,
      resultType: CameraResultType.Uri,
    });
    return photo.webPath!;
  } else {
    // On web: use file input
    return new Promise((resolve) => {
      const input = document.createElement('input');
      input.type = 'file';
      input.accept = 'image/*';
      input.onchange = () => {
        const file = input.files?.[0];
        if (file) resolve(URL.createObjectURL(file));
      };
      input.click();
    });
  }
}

Live Updates (Skip the App Store)

One of Ionic's killer features: deploy updates without going through App Store review. Since your app is web code loaded from local files, you can update those files remotely:

This is compliant with App Store guidelines as long as you don't change the app's primary purpose or add entirely new native features. For bug fixes, UI changes, and feature tweaks — it's a game-changer.

The Ecosystem in 2026

Ionic and Capacitor have a mature, stable ecosystem:

  • Capacitor 7 — latest major version with improved plugin APIs
  • Ionic Framework 8 — components for React, Angular, Vue, and Web Components
  • Appflow — CI/CD and live updates (commercial product from Ionic team)
  • Capgo — open-source alternative for live updates
  • Stencil — Ionic's Web Component compiler (powers Ionic components internally)
  • Enterprise plugins — biometrics, secure storage, SSO, managed app configuration

Who Uses Ionic + Capacitor?

  • T-Mobile — MyT-Mobile app
  • Sworkit — fitness app (millions of users)
  • MarketWatch — financial news
  • NHS — UK National Health Service apps
  • Sanvello — mental health platform
  • Thousands of enterprise apps — internal tools at Fortune 500 companies

Key Takeaways

  1. Ionic + Capacitor = your web app running inside a native shell with a bridge to device APIs
  2. Capacitor treats native projects as source code, not build artifacts — you can always drop to native when needed
  3. WebView performance in 2026 is excellent for business apps, content apps, and standard UIs
  4. The biggest advantage is code sharing — one codebase for web, iOS, and Android
  5. Live updates let you ship fixes without App Store review
  6. It's not the right choice for everything — games, AR, and heavily animated apps should look elsewhere

The "just a WebView" criticism misses the point. A WebView in 2026 is a full-featured, GPU-accelerated rendering engine backed by billions of dollars of browser engineering. For many apps, it's not a limitation — it's a superpower.


Series: Cross-Platform Mobile Development
Next: React Native: How JavaScript Renders Native UIs

📬 Subscribe to Newsletter

Get the latest blog posts delivered to your inbox every week. No spam, unsubscribe anytime.

We respect your privacy. Unsubscribe at any time.

💬 Comments

Sign in to leave a comment

We'll never post without your permission.