Getting Started
Ionic Setup
# Install Ionic CLI globally
npm install -g @ionic/cli
# Create a new Ionic app
ionic start myApp tabs
ionic start myApp blank
ionic start myApp sidemenu
# Run the app in the browser
ionic serve
# Add platforms
ionic capacitor add android
ionic capacitor add ios
# Build and run on device
ionic capacitor build android
ionic capacitor run android
npm install -g @ionic/cli
# Create a new Ionic app
ionic start myApp tabs
ionic start myApp blank
ionic start myApp sidemenu
# Run the app in the browser
ionic serve
# Add platforms
ionic capacitor add android
ionic capacitor add ios
# Build and run on device
ionic capacitor build android
ionic capacitor run android
Note: Make sure you have Node.js installed. For iOS development, you need a Mac with Xcode installed.
Basic App Structure
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
bootstrap: [AppComponent],
})
export class AppModule {}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
bootstrap: [AppComponent],
})
export class AppModule {}
Note: Ionic apps are built on Angular (or React/Vue) and follow their standard project structure with additional Ionic-specific components and services.
UI Components
Basic Components
// Button variants
<ion-button>Default Button</ion-button>
<ion-button color="primary">Primary</ion-button>
<ion-button color="secondary">Secondary</ion-button>
<ion-button color="danger">Danger</ion-button>
<ion-button fill="outline">Outline</ion-button>
<ion-button fill="clear">Clear</ion-button>
<ion-button size="small">Small</ion-button>
<ion-button size="large">Large</ion-button>
<ion-button expand="block">Block</ion-button>
<ion-button disabled>Disabled</ion-button>
// Input components
<ion-input placeholder="Enter input"></ion-input>
<ion-textarea placeholder="Enter text"></ion-textarea>
<ion-checkbox>Checkbox</ion-checkbox>
<ion-toggle>Toggle</ion-toggle>
<ion-range></ion-range>
<ion-select placeholder="Select option">
<ion-select-option value="option1">Option 1</ion-select-option>
<ion-select-option value="option2">Option 2</ion-select-option>
</ion-select>
<ion-button>Default Button</ion-button>
<ion-button color="primary">Primary</ion-button>
<ion-button color="secondary">Secondary</ion-button>
<ion-button color="danger">Danger</ion-button>
<ion-button fill="outline">Outline</ion-button>
<ion-button fill="clear">Clear</ion-button>
<ion-button size="small">Small</ion-button>
<ion-button size="large">Large</ion-button>
<ion-button expand="block">Block</ion-button>
<ion-button disabled>Disabled</ion-button>
// Input components
<ion-input placeholder="Enter input"></ion-input>
<ion-textarea placeholder="Enter text"></ion-textarea>
<ion-checkbox>Checkbox</ion-checkbox>
<ion-toggle>Toggle</ion-toggle>
<ion-range></ion-range>
<ion-select placeholder="Select option">
<ion-select-option value="option1">Option 1</ion-select-option>
<ion-select-option value="option2">Option 2</ion-select-option>
</ion-select>
Note: Ionic provides a wide range of UI components that automatically adapt to the platform (iOS or Android) look and feel.
Layout Components
// Grid system
<ion-grid>
<ion-row>
<ion-col>Column 1</ion-col>
<ion-col>Column 2</ion-col>
<ion-col>Column 3</ion-col>
</ion-row>
</ion-grid>
// Responsive grid
<ion-grid>
<ion-row>
<ion-col size="12" size-sm="6" size-md="4" size-lg="3">
Responsive Column
</ion-col>
</ion-row>
</ion-grid>
// Card component
<ion-card>
<ion-card-header>
<ion-card-title>Card Title</ion-card-title>
<ion-card-subtitle>Card Subtitle</ion-card-subtitle>
</ion-card-header>
<ion-card-content>
Card content goes here
</ion-card-content>
</ion-card>
// List component
<ion-list>
<ion-item>
<ion-label>Item 1</ion-label>
</ion-item>
<ion-item>
<ion-label>Item 2</ion-label>
</ion-item>
</ion-list>
<ion-grid>
<ion-row>
<ion-col>Column 1</ion-col>
<ion-col>Column 2</ion-col>
<ion-col>Column 3</ion-col>
</ion-row>
</ion-grid>
// Responsive grid
<ion-grid>
<ion-row>
<ion-col size="12" size-sm="6" size-md="4" size-lg="3">
Responsive Column
</ion-col>
</ion-row>
</ion-grid>
// Card component
<ion-card>
<ion-card-header>
<ion-card-title>Card Title</ion-card-title>
<ion-card-subtitle>Card Subtitle</ion-card-subtitle>
</ion-card-header>
<ion-card-content>
Card content goes here
</ion-card-content>
</ion-card>
// List component
<ion-list>
<ion-item>
<ion-label>Item 1</ion-label>
</ion-item>
<ion-item>
<ion-label>Item 2</ion-label>
</ion-item>
</ion-list>
Note: Ionic's grid system is based on CSS Flexbox and provides a responsive 12-column layout that works across all screen sizes.
Navigation Components
// Tabs component
<ion-tabs>
<ion-tab-bar slot="bottom">
<ion-tab-button tab="tab1">
<ion-icon name="home"></ion-icon>
<ion-label>Home</ion-label>
</ion-tab-button>
<ion-tab-button tab="tab2">
<ion-icon name="settings"></ion-icon>
<ion-label>Settings</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
// Menu component
<ion-menu contentId="main-content">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item>Menu Item 1</ion-item>
<ion-item>Menu Item 2</ion-item>
</ion-list>
</ion-content>
</ion-menu>
<ion-app>
<ion-router-outlet id="main-content"></ion-router-outlet>
</ion-app>
<ion-tabs>
<ion-tab-bar slot="bottom">
<ion-tab-button tab="tab1">
<ion-icon name="home"></ion-icon>
<ion-label>Home</ion-label>
</ion-tab-button>
<ion-tab-button tab="tab2">
<ion-icon name="settings"></ion-icon>
<ion-label>Settings</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
// Menu component
<ion-menu contentId="main-content">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item>Menu Item 1</ion-item>
<ion-item>Menu Item 2</ion-item>
</ion-list>
</ion-content>
</ion-menu>
<ion-app>
<ion-router-outlet id="main-content"></ion-router-outlet>
</ion-app>
Advanced Components
// Modal component
async function presentModal() {
const modal = await modalController.create({
component: ModalPage,
componentProps: {
'prop1': value1,
'prop2': value2
}
});
return await modal.present();
}
// Loading component
async function showLoading() {
const loading = await loadingController.create({
message: 'Please wait...',
duration: 2000
});
await loading.present();
}
// Toast component
async function showToast() {
const toast = await toastController.create({
message: 'Your settings have been saved.',
duration: 2000
});
await toast.present();
}
// Alert component
async function showAlert() {
const alert = await alertController.create({
header: 'Alert',
message: 'This is an alert message.',
buttons: ['OK']
});
await alert.present();
}
async function presentModal() {
const modal = await modalController.create({
component: ModalPage,
componentProps: {
'prop1': value1,
'prop2': value2
}
});
return await modal.present();
}
// Loading component
async function showLoading() {
const loading = await loadingController.create({
message: 'Please wait...',
duration: 2000
});
await loading.present();
}
// Toast component
async function showToast() {
const toast = await toastController.create({
message: 'Your settings have been saved.',
duration: 2000
});
await toast.present();
}
// Alert component
async function showAlert() {
const alert = await alertController.create({
header: 'Alert',
message: 'This is an alert message.',
buttons: ['OK']
});
await alert.present();
}
Theming & Styling
CSS Variables
// Global theming in variables.css
:root {
/* Primary colors */
--ion-color-primary: #3880ff;
--ion-color-primary-rgb: 56, 128, 255;
--ion-color-primary-contrast: #ffffff;
--ion-color-primary-contrast-rgb: 255, 255, 255;
--ion-color-primary-shade: #3171e0;
--ion-color-primary-tint: #4c8dff;
/* Secondary colors */
--ion-color-secondary: #3dc2ff;
--ion-color-secondary-rgb: 61, 194, 255;
--ion-color-secondary-contrast: #ffffff;
--ion-color-secondary-contrast-rgb: 255, 255, 255;
--ion-color-secondary-shade: #36abe0;
--ion-color-secondary-tint: #50c8ff;
/* Font family */
--ion-font-family: 'Roboto', sans-serif;
/* Background and text colors */
--ion-background-color: #f4f5f8;
--ion-text-color: #222428;
}
// Dark theme
@media (prefers-color-scheme: dark) {
:root {
--ion-background-color: #121212;
--ion-text-color: #ffffff;
}
}
// Using CSS variables in components
.my-custom-class {
background: var(--ion-color-primary);
color: var(--ion-color-primary-contrast);
font-family: var(--ion-font-family);
padding: 16px;
}
:root {
/* Primary colors */
--ion-color-primary: #3880ff;
--ion-color-primary-rgb: 56, 128, 255;
--ion-color-primary-contrast: #ffffff;
--ion-color-primary-contrast-rgb: 255, 255, 255;
--ion-color-primary-shade: #3171e0;
--ion-color-primary-tint: #4c8dff;
/* Secondary colors */
--ion-color-secondary: #3dc2ff;
--ion-color-secondary-rgb: 61, 194, 255;
--ion-color-secondary-contrast: #ffffff;
--ion-color-secondary-contrast-rgb: 255, 255, 255;
--ion-color-secondary-shade: #36abe0;
--ion-color-secondary-tint: #50c8ff;
/* Font family */
--ion-font-family: 'Roboto', sans-serif;
/* Background and text colors */
--ion-background-color: #f4f5f8;
--ion-text-color: #222428;
}
// Dark theme
@media (prefers-color-scheme: dark) {
:root {
--ion-background-color: #121212;
--ion-text-color: #ffffff;
}
}
// Using CSS variables in components
.my-custom-class {
background: var(--ion-color-primary);
color: var(--ion-color-primary-contrast);
font-family: var(--ion-font-family);
padding: 16px;
}
Platform Styles
// Using platform detection
import { Platform } from '@ionic/angular';
constructor(private platform: Platform) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
// Check if running on iOS
if (this.platform.is('ios')) {
// Apply iOS specific styles or logic
this.applyIosStyles();
}
// Check if running on Android
if (this.platform.is('android')) {
// Apply Android specific styles or logic
this.applyAndroidStyles();
}
// Check if running on capacitor
if (this.platform.is('capacitor')) {
// Native functionality available
this.enableNativeFeatures();
}
});
}
// Platform-specific SCSS
.ios {
.header-class {
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
}
}
.md {
.header-class {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
}
import { Platform } from '@ionic/angular';
constructor(private platform: Platform) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
// Check if running on iOS
if (this.platform.is('ios')) {
// Apply iOS specific styles or logic
this.applyIosStyles();
}
// Check if running on Android
if (this.platform.is('android')) {
// Apply Android specific styles or logic
this.applyAndroidStyles();
}
// Check if running on capacitor
if (this.platform.is('capacitor')) {
// Native functionality available
this.enableNativeFeatures();
}
});
}
// Platform-specific SCSS
.ios {
.header-class {
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
}
}
.md {
.header-class {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
}
Note: Ionic automatically adapts its components to match the design language of the platform (iOS or Material Design), but you can also customize this behavior.
Native Functionality
Cordova/Capacitor Plugins
// Using Camera plugin
import { Camera, CameraResultType } from '@capacitor/camera';
async takePicture() {
const image = await Camera.getPhoto({
quality: 90,
allowEditing: true,
resultType: CameraResultType.Uri
});
// image.webPath will contain a path that can be set as an image src
this.imageUrl = image.webPath;
}
// Using Geolocation plugin
import { Geolocation } from '@capacitor/geolocation';
async getCurrentPosition() {
const coordinates = await Geolocation.getCurrentPosition();
this.latitude = coordinates.coords.latitude;
this.longitude = coordinates.coords.longitude;
}
// Using Storage plugin
import { Storage } from '@capacitor/storage';
async setData() {
await Storage.set({
key: 'user',
value: JSON.stringify({
name: 'John',
age: 30
})
});
}
async getData() {
const item = await Storage.get({ key: 'user' });
this.user = JSON.parse(item.value);
}
import { Camera, CameraResultType } from '@capacitor/camera';
async takePicture() {
const image = await Camera.getPhoto({
quality: 90,
allowEditing: true,
resultType: CameraResultType.Uri
});
// image.webPath will contain a path that can be set as an image src
this.imageUrl = image.webPath;
}
// Using Geolocation plugin
import { Geolocation } from '@capacitor/geolocation';
async getCurrentPosition() {
const coordinates = await Geolocation.getCurrentPosition();
this.latitude = coordinates.coords.latitude;
this.longitude = coordinates.coords.longitude;
}
// Using Storage plugin
import { Storage } from '@capacitor/storage';
async setData() {
await Storage.set({
key: 'user',
value: JSON.stringify({
name: 'John',
age: 30
})
});
}
async getData() {
const item = await Storage.get({ key: 'user' });
this.user = JSON.parse(item.value);
}
Device APIs
// Using Device information
import { Device } from '@capacitor/device';
async getDeviceInfo() {
const info = await Device.getInfo();
console.log('Device model:', info.model);
console.log('Platform:', info.platform);
}
async getBatteryInfo() {
const info = await Device.getBatteryInfo();
console.log('Battery level:', info.batteryLevel);
console.log('Is charging:', info.isCharging);
}
// Using Network information
import { Network } from '@capacitor/network';
async getNetworkStatus() {
const status = await Network.getStatus();
console.log('Network connected:', status.connected);
console.log('Connection type:', status.connectionType);
}
// Listen for network changes
Network.addListener('networkStatusChange', (status) => {
console.log('Network status changed', status);
});
// Using Share API
import { Share } from '@capacitor/share';
async shareContent() {
await Share.share({
title: 'Check out this app',
text: 'I found this amazing app...',
url: 'https://ionicframework.com/',
dialogTitle: 'Share with friends',
});
}
import { Device } from '@capacitor/device';
async getDeviceInfo() {
const info = await Device.getInfo();
console.log('Device model:', info.model);
console.log('Platform:', info.platform);
}
async getBatteryInfo() {
const info = await Device.getBatteryInfo();
console.log('Battery level:', info.batteryLevel);
console.log('Is charging:', info.isCharging);
}
// Using Network information
import { Network } from '@capacitor/network';
async getNetworkStatus() {
const status = await Network.getStatus();
console.log('Network connected:', status.connected);
console.log('Connection type:', status.connectionType);
}
// Listen for network changes
Network.addListener('networkStatusChange', (status) => {
console.log('Network status changed', status);
});
// Using Share API
import { Share } from '@capacitor/share';
async shareContent() {
await Share.share({
title: 'Check out this app',
text: 'I found this amazing app...',
url: 'https://ionicframework.com/',
dialogTitle: 'Share with friends',
});
}
Note: Capacitor provides a consistent API for accessing native device features across iOS, Android, and the web. Most plugins work on all platforms with the same code.