Skip to content
Ionic Framework Guide — Hybrid Mobile Apps with Angular/React/Vue

Ionic Framework Guide — Hybrid Mobile Apps with Angular/React/Vue

DodaTech Updated Jun 7, 2026 9 min read

Ionic Framework is an open-source UI toolkit for building performant, cross-platform mobile and desktop apps using web technologies (Angular, React, or Vue) with a library of native-style UI components and seamless access to device APIs through Capacitor or Cordova.

What You’ll Learn

You’ll use the Ionic CLI to scaffold apps, choose between Capacitor and Cordova for native access, build UIs with Ionic’s component library, customize themes with CSS variables, implement navigation with Angular Router or React Router, and deploy as both native apps and PWAs.

Why Ionic Matters

Ionic is the most popular hybrid mobile framework, powering over 5 million apps worldwide. It bridges the gap between web development and native mobile — one codebase deploys to iOS, Android, and the web as a Progressive Web App. DodaTech’s customer portal uses Ionic because it needs to reach users on every platform while maintaining a single development team that writes TypeScript, not platform-specific languages.

Ionic Learning Path

    flowchart LR
  A[Angular/React/Vue] --> B[Ionic CLI]
  B --> C[Ionic Components]
  C --> D[Theming & Styling]
  D --> E[Navigation & Routing]
  E --> F[Capacitor / Cordova]
  F --> G[Native APIs]
  G --> H[App Store / PWA]
  B:::current

  classDef current fill:#498AFF,color:#fff,stroke:#333,stroke-width:2px
  
Prerequisites: Working knowledge of Angular, React, or Vue. Solid JavaScript and TypeScript fundamentals are expected.

Getting Started with Ionic CLI

# Install the Ionic CLI globally
npm install -g @ionic/cli

# Create a new Ionic app
ionic start dodatech-app tabs --type=angular
# Options: --type=angular | --type=react | --type=vue

cd dodatech-app
ionic serve  # Opens in browser with live reload

The CLI scaffolds a complete project with routing, theming, and a tab-based layout:

dodatech-app/
├── src/
│   ├── app/
│   │   ├── pages/              # Page components
│   │   ├── tabs/               # Tab navigation
│   │   └── app-routing.module.ts
│   ├── theme/
│   │   └── variables.css       # CSS custom properties
│   ├── assets/
│   └── index.html
├── capacitor.config.ts
├── ionic.config.json
└── package.json

UI Components

Ionic provides over 50 native-style UI components that adapt to each platform:

<!-- Angular component example -->
<ion-header>
  <ion-toolbar color="primary">
    <ion-title>DodaTech Scanner</ion-title>
    <ion-buttons slot="end">
      <ion-button (click)="showSettings()">
        <ion-icon slot="icon-only" name="settings-outline"></ion-icon>
      </ion-button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>

<ion-content>
  <!-- Search bar -->
  <ion-searchbar 
    [(ngModel)]="searchQuery"
    (ionInput)="searchDevices($event)"
    placeholder="Search devices..."
    animated>
  </ion-searchbar>

  <!-- Device list with pull-to-refresh -->
  <ion-refresher slot="fixed" (ionRefresh)="refreshList($event)">
    <ion-refresher-content></ion-refresher-content>
  </ion-refresher>

  <ion-list>
    <ion-item-sliding *ngFor="let device of filteredDevices">
      <ion-item (click)="viewDevice(device)">
        <ion-icon :name="device.icon" slot="start" color="medium"></ion-icon>
        <ion-label>
          <h2>{{ device.name }}</h2>
          <p>{{ device.type }} · {{ device.signalStrength }} dBm</p>
        </ion-label>
        <ion-chip slot="end" [color]="device.isConnected ? 'success' : 'medium'">
          {{ device.isConnected ? 'Online' : 'Offline' }}
        </ion-chip>
      </ion-item>

      <ion-item-options side="end">
        <ion-item-option color="primary" (click)="editDevice(device)">
          <ion-icon slot="icon-only" name="create-outline"></ion-icon>
        </ion-item-option>
        <ion-item-option color="danger" (click)="deleteDevice(device)">
          <ion-icon slot="icon-only" name="trash-outline"></ion-icon>
        </ion-item-option>
      </ion-item-options>
    </ion-item-sliding>
  </ion-list>

  <!-- Floating action button -->
  <ion-fab vertical="bottom" horizontal="end" slot="fixed">
    <ion-fab-button (click)="addDevice()">
      <ion-icon name="add"></ion-icon>
    </ion-fab-button>
  </ion-fab>
</ion-content>

Output: The page renders with a native-style header, search bar with animation, a pull-to-refresh list of devices with swipeable action buttons (edit/delete), and a floating action button. On iOS, the components mimic UIKit styling. On Android, they follow Material Design guidelines — automatically.

Theming with CSS Variables

Ionic uses CSS custom properties (variables) for complete theming control:

/* src/theme/variables.css */

/* Light theme */
:root {
  --ion-color-primary: #2c3e50;
  --ion-color-primary-rgb: 44, 62, 80;
  --ion-color-primary-contrast: #ffffff;
  
  --ion-color-secondary: #3498db;
  --ion-color-secondary-rgb: 52, 152, 219;
  --ion-color-secondary-contrast: #ffffff;
  
  --ion-color-tertiary: #27ae60;
  --ion-color-tertiary-rgb: 39, 174, 96;
  --ion-color-tertiary-contrast: #ffffff;
  
  --ion-background-color: #f8f9fa;
  --ion-text-color: #2c3e50;
  --ion-toolbar-background: #2c3e50;
  --ion-toolbar-color: #ffffff;
}

/* Dark theme (auto-detected from system preference) */
@media (prefers-color-scheme: dark) {
  :root {
    --ion-color-primary: #4a6fa5;
    --ion-color-secondary: #5dade2;
    --ion-background-color: #1a1a2e;
    --ion-text-color: #ecf0f1;
    --ion-toolbar-background: #16213e;
    --ion-toolbar-color: #ecf0f1;
    
    --ion-item-background: #1a1a2e;
    --ion-card-background: #16213e;
  }
}

Output: The entire app adopts the custom color scheme. Primary buttons, headers, and accents use the defined colors. The dark theme activates automatically when the user’s operating system is in dark mode. Every Ionic component respects these variables without additional CSS changes.

Navigation and Routing

Ionic integrates with the framework’s router. Here’s an Angular example:

// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  {
    path: '',
    redirectTo: '/devices',
    pathMatch: 'full'
  },
  {
    path: 'devices',
    loadChildren: () => import('./pages/devices/devices.module').then(m => m.DevicesPageModule)
  },
  {
    path: 'devices/:id',
    loadChildren: () => import('./pages/device-detail/device-detail.module').then(m => m.DeviceDetailPageModule)
  },
  {
    path: 'settings',
    loadChildren: () => import('./pages/settings/settings.module').then(m => m.SettingsPageModule)
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}
<!-- Device detail page with Ionic navigation -->
<ion-header>
  <ion-toolbar>
    <ion-buttons slot="start">
      <ion-back-button defaultHref="/devices"></ion-back-button>
    </ion-buttons>
    <ion-title>{{ device.name }}</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <ion-card>
    <ion-card-header>
      <ion-card-title>{{ device.name }}</ion-card-title>
      <ion-card-subtitle>{{ device.type }}</ion-card-subtitle>
    </ion-card-header>
    
    <ion-card-content>
      <ion-list>
        <ion-item>
          <ion-icon name="wifi-outline" slot="start"></ion-icon>
          <ion-label>Signal Strength</ion-label>
          <ion-note slot="end">{{ device.signalStrength }} dBm</ion-note>
        </ion-item>
        <ion-item>
          <ion-icon name="location-outline" slot="start"></ion-icon>
          <ion-label>Location</ion-label>
          <ion-note slot="end">{{ device.location }}</ion-note>
        </ion-item>
        <ion-item>
          <ion-icon name="calendar-outline" slot="start"></ion-icon>
          <ion-label>Last Seen</ion-label>
          <ion-note slot="end">{{ device.lastSeen | date }}</ion-note>
        </ion-item>
      </ion-list>
    </ion-card-content>
  </ion-card>
</ion-content>

Output: Navigating to /devices/123 shows the device detail page with a native-style back button that returns to the device list. The page transition animation matches the platform (iOS slide-from-left or Android fade).

Capacitor vs Cordova

Ionic works with both native bridge technologies:

FeatureCapacitorCordova
ArchitectureModern, plugin-basedLegacy, plugin-based
JavaScript → NativeDirect bridgeWebView injection
PWA supportBuilt-inManual
Plugin ecosystemGrowing fastMature, extensive
Modern toolingWeb-first, TypeScriptNode-based
# Capacitor commands
ionic capacitor add ios
ionic capacitor add android
ionic capacitor copy    # Copy web build to native project
ionic capacitor sync   # Copy + update native dependencies
ionic capacitor open   # Open native IDE

# Build and run
ionic build            # Build web assets
ionic capacitor run ios --livereload  # iOS with live reload
ionic capacitor run android           # Android

Capacitor Native API Example

// Using Capacitor plugins for native features
import { Plugins } from '@capacitor/core';
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { Geolocation } from '@capacitor/geolocation';
import { Share } from '@capacitor/share';
import { LocalNotifications } from '@capacitor/local-notifications';

export class DeviceService {
  async capturePhoto(): Promise<string> {
    const image = await Camera.getPhoto({
      quality: 90,
      allowEditing: false,
      resultType: CameraResultType.Uri,
      source: CameraSource.Camera
    });
    
    return image.webPath!;
  }

  async getCurrentLocation() {
    const position = await Geolocation.getCurrentPosition({
      enableHighAccuracy: true,
      timeout: 10000
    });
    
    return {
      latitude: position.coords.latitude,
      longitude: position.coords.longitude
    };
  }

  async shareDevice(device: Device) {
    await Share.share({
      title: device.name,
      text: `Check out ${device.name} — a ${device.type} with signal strength ${device.signalStrength} dBm`,
      url: `https://dodatech.com/devices/${device.id}`,
      dialogTitle: 'Share Device'
    });
  }

  async notifyScanComplete(count: number) {
    await LocalNotifications.schedule({
      notifications: [{
        title: 'Scan Complete',
        body: `Found ${count} device(s) nearby`,
        id: 1,
        schedule: { at: new Date(Date.now() + 1000) },
        sound: 'default'
      }]
    });
  }
}

Output: capturePhoto() opens the native camera, returns the image URI. getCurrentLocation() uses native GPS. shareDevice() triggers the OS share sheet. notifyScanComplete() posts a system notification. All APIs work identically on iOS and Android with no platform-specific code.

PWA Support

Ionic apps are PWAs by default. Deploy the same codebase as a web app:

# Build for web
ionic build --prod

# Deploy the www/ folder to any static host
npx cap sync

PWAs built with Ionic include:

  • Offline support via service workers
  • Add-to-home-screen prompt
  • Full-screen mode
  • Push notifications (with Capacitor)

Common Mistakes Beginners Make

  1. Using Cordova when Capacitor is better for new projects: Cordova is mature but Capacitor offers better performance, modern tooling, and PWA support. Use Cordova only if you need a specific legacy plugin.

  2. Not using ion-input for forms: Standard HTML inputs don’t get Ionic’s theming, touch-friendly sizing, or validation styling. Always use Ionic components (ion-input, ion-select, ion-textarea).

  3. Forgetting to handle hardware back button: Android’s hardware back button needs special handling in Ionic apps. Use Platform.backButton subscription to manage custom back behavior.

  4. Overusing modals for simple interactions: Modals are heavyweight. Use ion-popover or inline content for simple forms and confirmations to keep navigation fluid.

  5. Not optimizing images for mobile: Large images cause slow scroll performance and high memory usage on mobile devices. Use lazy loading and compress images to appropriate resolutions.

  6. Ignoring iOS safe areas: Notched iPhones have safe areas for the notch and home indicator. Use ion-content with proper padding or CSS safe-area-inset-* variables.

Practice Questions

  1. What is the difference between Capacitor and Cordova?
  2. How do you customize Ionic’s default colors?
  3. What is the purpose of ion-back-button?
  4. How do you deploy an Ionic app as a PWA?
  5. Why use Ionic components instead of standard HTML elements?

Answers:

  1. Capacitor is a modern native bridge with better PWA support, direct JavaScript→native communication, and a plugin system designed for TypeScript. Cordova is the older alternative with a larger but aging plugin ecosystem.
  2. Override CSS custom properties in src/theme/variables.css like --ion-color-primary, --ion-background-color, and --ion-text-color.
  3. It provides a back button that returns to the previous page in the navigation stack, styled natively per platform.
  4. Run ionic build --prod to generate the www/ folder with service worker and manifest. Deploy to any static web host.
  5. Ionic components are touch-optimized, platform-adaptive (iOS/Material Design), accessible, and fully integrated with Ionic’s theming system.

Challenge

Build a complete inventory management app with Ionic: use tabs for navigation (Items, Scan, Settings), implement barcode scanning with Capacitor plugin, store data in local storage, support dark mode toggle, and add push notifications for low-stock alerts.

Real-World Task

Create a field service report app: capture photos with Capacitor Camera, record location with Geolocation, auto-generate PDF reports, provide offline storage with sync-on-connectivity, and deploy as both an Android app and a PWA.

FAQ

Do I need to know native mobile development for Ionic?
: No. Ionic handles the native layer through Capacitor. You write all code in TypeScript/JavaScript. For advanced native features, some platform knowledge helps, but it’s not required.
Can I use Ionic with React or Vue?
: Yes. Ionic supports Angular, React, and Vue. The CLI lets you choose your framework when creating a project. All components work identically across frameworks.
How does Ionic compare to Flutter?
: Ionic uses web technologies (HTML/CSS/JS) rendered in a WebView with native API access. Flutter uses Dart with custom rendering. Ionic is better for web developers; Flutter offers more consistent performance.
Is Ionic free?
: Yes. Ionic Framework is open source (MIT license). Capacitor is also open source. Ionic Appflow (CI/CD) has paid tiers, but the core framework is free.
Does Ionic support desktop apps?
: Yes. Ionic apps run as Electron desktop apps using Capacitor’s Electron integration. The same codebase targets iOS, Android, web, and desktop.

Try It Yourself

ionic start dodatech-app tabs --type=angular
cd dodatech-app
ionic serve

Add a new tab page for device scanning with ion-searchbar, display results in an ion-list with swipeable items, add a settings page with dark mode toggle that changes CSS variables, and test on a mobile device with ionic capacitor run android.

What’s Next

Related topics: Angular, JavaScript, TypeScript, Capacitor

What’s Next

Congratulations on completing this Ionic Framework tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro