Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Ionic Framework User Guide

Generated June 2026 from ionic-team/ionic-framework at 3da72cd

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Ionic is an open-source app development toolkit for building modern, fast, cross-platform applications from a single codebase using standard web technologies. It ships as a set of Web Components (custom elements such as <ion-button> and <ion-modal>) plus thin integration packages for the three major frameworks — Angular, React, and Vue — so you write your UI once and run it as a native mobile app, a desktop app, or a Progressive Web App (PWA).

This guide is for developers building applications with Ionic. It covers installation, the component catalog, theming, navigation, overlays, animations, gestures, and configuration. It documents the framework exactly as it behaves in the source at the version stamped in the footer — not what older tutorials or blog posts may claim.

Note

This guide documents @ionic/core and the framework integration packages (@ionic/angular, @ionic/react, @ionic/vue) version 8.8.9. The components are identical across all frameworks because they are all the same underlying Web Components — only the way you import and bind to them changes.


1. Quick Start

The fastest way to start is with the Ionic CLI, which scaffolds a complete project for your chosen framework with routing, theming, and a sample page already wired up.

Important

The Ionic CLI (@ionic/cli) is a separate tool from this framework package. It is the recommended entry point for new projects because it generates the correct project structure and installs the matching @ionic/{angular,react,vue} package for you.

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

Angular

ionic start myApp tabs --type=angular
cd myApp
ionic serve

React

ionic start myApp tabs --type=react
cd myApp
ionic serve

Vue

ionic start myApp tabs --type=vue
cd myApp
ionic serve
> ionic serve
[INFO] Development server running!
       Local: http://localhost:8100
[INFO] Browser window opened to http://localhost:8100!

ionic serve opens a live-reloading development server in your browser. From here you build with the components and APIs described in the rest of this guide.

Tip

The tabs argument selects a starter template. Other built-in starters include blank, sidemenu, and list. Run ionic start --list to see all available starters for each framework.


2. Installation

You can add Ionic to an existing project without the CLI by installing the framework package directly. Pick the section that matches your framework.

2.1 Angular

npm install @ionic/angular @ionic/angular-toolkit

@ionic/angular requires the following peer dependencies (declared in the package):

Peer dependency Required version
@angular/core >=16.0.0
@angular/forms >=16.0.0
@angular/router >=16.0.0
rxjs >=7.5.0
zone.js >=0.13.0

Warning

Angular 16 is the minimum supported version. Newer Angular major versions are supported as they ship, but verify compatibility before upgrading — for example, full Angular 21 support and native Vitest support are still being tracked in the issue tracker at the time this guide was generated.

2.2 React

npm install @ionic/react @ionic/react-router

@ionic/react is built for React applications and @ionic/react-router provides the routing integration layered on top of react-router.

2.3 Vue

npm install @ionic/vue @ionic/vue-router

@ionic/vue targets Vue 3. @ionic/vue-router wraps vue-router so that Ionic's page transitions and navigation stack work correctly.

2.4 Vanilla / Web Components (no framework)

Because Ionic is built on standard custom elements, you can use it with no framework at all by installing @ionic/core directly:

npm install @ionic/core

@ionic/core declares these runtime dependencies:

Dependency Version Purpose
@stencil/core 4.43.5 Web Component runtime the components are compiled with
ionicons ^8.0.13 The icon set used by <ion-icon>
tslib ^2.1.0 TypeScript runtime helpers

Note

For native mobile features (camera, filesystem, geolocation, haptics, keyboard, status bar), Ionic apps use Capacitor. @ionic/core lists Capacitor 8 packages (@capacitor/haptics, @capacitor/keyboard, @capacitor/status-bar) as integration points. Capacitor is installed and configured separately; this guide focuses on the UI framework.


3. Core Concepts

Understanding four ideas will make everything else in this guide click into place.

3.1 Everything is a Web Component

Every Ionic UI element is a custom HTML element whose tag begins with ion-. The framework packages do not reimplement these elements — they generate lightweight wrappers that let you use the same elements idiomatically in Angular templates, JSX, or Vue templates.

<ion-button color="primary">Click me</ion-button>

Because they are real DOM elements, they work with standard attributes, events, and CSS.

3.2 The App Shell: <ion-app>

Every Ionic application is wrapped in a single <ion-app> element. It is the root container that the navigation, overlays, and gesture systems anchor to. Inside it you typically place a router outlet or a menu.

<ion-app>
  <ion-router-outlet></ion-router-outlet>
</ion-app>

3.3 Pages and <ion-content>

A "page" is a component containing a header, scrollable content, and optionally a footer:

<ion-header>
  <ion-toolbar>
    <ion-title>My Page</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content class="ion-padding">
  <p>Your scrollable content goes here.</p>
</ion-content>

<ion-footer>
  <ion-toolbar>
    <ion-title>Footer</ion-title>
  </ion-toolbar>
</ion-footer>

<ion-content> provides the scroll container and is required for most layout features (refreshers, infinite scroll, fixed FABs) to work.

3.4 Modes: ios and md

Ionic ships two design languages and picks one automatically based on the device:

  • ios — Apple's iOS look and feel
  • md — Google's Material Design

The active mode is called the mode and is exposed by getMode(). When no mode is configured, the framework defaults to md. You can force a single mode app-wide through configuration (see §13 Configuration) or per-component with the mode attribute:

<ion-button mode="ios">Always iOS styled</ion-button>

Tip

Designing with both modes in mind is what makes an Ionic app feel native on each platform. Let the default automatic detection do the work unless you have a specific reason to lock a single mode.


4. Framework Integration

The components are identical everywhere; only setup and binding differ. Read the section for your framework.

4.1 Angular

Ionic supports two Angular styles: the classic NgModule approach and the modern standalone approach.

Standalone (recommended for new apps):

// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideIonicAngular } from '@ionic/angular/standalone';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideIonicAngular(),
  ],
});

With standalone components you import the individual Ionic components you use:

import { Component } from '@angular/core';
import { IonButton, IonContent, IonHeader, IonTitle, IonToolbar } from '@ionic/angular/standalone';

@Component({
  selector: 'app-home',
  standalone: true,
  imports: [IonButton, IonContent, IonHeader, IonTitle, IonToolbar],
  template: `
    <ion-header><ion-toolbar><ion-title>Home</ion-title></ion-toolbar></ion-header>
    <ion-content class="ion-padding">
      <ion-button>Tap</ion-button>
    </ion-content>
  `,
})
export class HomeComponent {}

NgModule (classic):

import { NgModule } from '@angular/core';
import { IonicModule } from '@ionic/angular';

@NgModule({
  imports: [IonicModule.forRoot()],
})
export class AppModule {}

Both provideIonicAngular(config) and IonicModule.forRoot(config) accept an Ionic configuration object (see §13).

Important

For navigation to work, register Ionic's route reuse strategy. With standalone you add it to providers; with NgModule it is wired through IonicRouteStrategy:

import { RouteReuseStrategy } from '@angular/router';
import { IonicRouteStrategy } from '@ionic/angular';

providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }]

Angular also provides controller services (injectable equivalents of the programmatic overlay APIs): AlertController, ActionSheetController, ModalController, LoadingController, PickerController, PopoverController, ToastController, MenuController, AnimationController, GestureController, plus Platform, NavController, Config, and DomController.

4.2 React

Initialize Ionic once and wrap your app in <IonApp> and a router:

// App.tsx
import { IonApp, IonRouterOutlet, setupIonicReact } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import { Route } from 'react-router-dom';
import Home from './pages/Home';

setupIonicReact();

const App: React.FC = () => (
  <IonApp>
    <IonReactRouter>
      <IonRouterOutlet>
        <Route exact path="/home" component={Home} />
      </IonRouterOutlet>
    </IonReactRouter>
  </IonApp>
);

export default App;

setupIonicReact(config) accepts the same configuration object as the other frameworks. @ionic/react-router also exports IonReactMemoryRouter and IonReactHashRouter for in-memory and hash-based routing.

React components are used as JSX:

import { IonButton, IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';

const Home: React.FC = () => (
  <IonPage>
    <IonHeader>
      <IonToolbar><IonTitle>Home</IonTitle></IonToolbar>
    </IonHeader>
    <IonContent className="ion-padding">
      <IonButton>Tap</IonButton>
    </IonContent>
  </IonPage>
);

4.3 Vue

Install the Ionic plugin and the router:

// main.ts
import { createApp } from 'vue';
import { IonicVue } from '@ionic/vue';
import { createRouter, createWebHistory } from '@ionic/vue-router';
import App from './App.vue';
import { routes } from './router';

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes,
});

const app = createApp(App).use(IonicVue).use(router);

router.isReady().then(() => app.mount('#app'));

app.use(IonicVue, config) accepts the shared configuration object. @ionic/vue-router exports createRouter, createWebHistory, createWebHashHistory, and createMemoryHistory — these wrap the equivalents from vue-router so that Ionic's view stack and transitions work correctly.

Components are used in templates after importing them:

<script setup lang="ts">
import { IonButton, IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/vue';
</script>

<template>
  <ion-page>
    <ion-header><ion-toolbar><ion-title>Home</ion-title></ion-toolbar></ion-header>
    <ion-content class="ion-padding">
      <ion-button>Tap</ion-button>
    </ion-content>
  </ion-page>
</template>

5. Component Catalog

Ionic ships roughly one hundred components. The catalog below groups every component by purpose. For frequently used components you will find a working example; all components are listed in reference tables so you can discover what exists. In Angular and Vue, use the kebab-case tag (<ion-button>); in React, use the PascalCase JSX name (<IonButton>).

Note

Component properties are set as HTML attributes (kebab-case) or JSX props (camelCase). Events use the ion-prefixed name (e.g. ionChange). The authoritative per-component property and event list is published on the official component reference; this guide documents structure, usage patterns, and the most commonly used props.

5.1 App Shell & Layout

Component Purpose
ion-app Root container for the entire application (exactly one per app)
ion-content Primary scrollable content area of a page
ion-header Top region of a page, typically holds a toolbar
ion-footer Bottom region of a page
ion-toolbar Bar that holds a title and buttons; used in headers and footers
ion-title Title text inside a toolbar
ion-buttons Container that positions buttons within a toolbar (slot="start"/"end")
ion-grid Responsive 12-column flexbox grid
ion-row A row within a grid
ion-col A column within a row, with responsive size attributes
ion-split-pane Two-pane layout that shows a side menu next to content on larger screens
ion-backdrop Semi-transparent overlay behind menus and overlays
<ion-grid>
  <ion-row>
    <ion-col size="12" size-md="6">Left</ion-col>
    <ion-col size="12" size-md="6">Right</ion-col>
  </ion-row>
</ion-grid>

size="12" makes the column full width on all screens; size-md="6" makes it half width from the medium breakpoint up.

5.2 Navigation

Component Purpose
ion-router-outlet Renders the matched route and animates page transitions
ion-nav Imperative navigation stack (push/pop) for non-URL navigation
ion-nav-link Declarative trigger for ion-nav push/pop/root navigation
ion-tabs Tabbed navigation container
ion-tab-bar The bar that holds tab buttons
ion-tab-button A single button within a tab bar
ion-tab A tab's content area
ion-menu Slide-out side navigation menu
ion-menu-button Button that toggles the menu
ion-menu-toggle Wrapper that toggles the menu when its child is activated
ion-back-button Navigates to the previous page
ion-breadcrumb / ion-breadcrumbs Breadcrumb trail navigation
ion-router / ion-route / ion-route-redirect / ion-router-link Vanilla (non-framework) routing elements used by @ionic/core
<ion-tabs>
  <ion-tab-bar slot="bottom">
    <ion-tab-button tab="home">
      <ion-icon name="home"></ion-icon>
      <ion-label>Home</ion-label>
    </ion-tab-button>
    <ion-tab-button tab="settings">
      <ion-icon name="settings"></ion-icon>
      <ion-label>Settings</ion-label>
    </ion-tab-button>
  </ion-tab-bar>
</ion-tabs>

Note

The ion-router, ion-route, and related elements are the routing primitives for vanilla Web Component projects. In Angular, React, and Vue you use the framework's own router (Angular Router, React Router, Vue Router) bridged through @ionic/angular, @ionic/react-router, and @ionic/vue-router respectively. See §9 Navigation & Routing.

5.3 Buttons & Actions

Component Purpose
ion-button Standard button (fill, expand, shape, size, color props)
ion-fab Floating action button container
ion-fab-button The floating action button itself
ion-fab-list Group of FAB buttons revealed when the main FAB is activated
ion-ripple-effect Material ripple feedback on tap
<ion-button expand="block" fill="solid" color="primary">Submit</ion-button>
<ion-button fill="outline">Outline</ion-button>
<ion-button fill="clear" size="small">Clear</ion-button>

<ion-fab vertical="bottom" horizontal="end" slot="fixed">
  <ion-fab-button>
    <ion-icon name="add"></ion-icon>
  </ion-fab-button>
</ion-fab>

5.4 Inputs & Forms

Component Purpose
ion-input Single-line text input (and number, email, password, etc.)
ion-textarea Multi-line text input
ion-checkbox Checkbox
ion-radio / ion-radio-group Radio button and its group
ion-toggle On/off switch
ion-range Slider for selecting a value or range
ion-select / ion-select-option Dropdown select and its options
ion-select-modal / ion-select-popover Internal presentation surfaces for ion-select
ion-searchbar Search input with clear/cancel affordances
ion-datetime Calendar / time picker
ion-datetime-button Compact button that opens an ion-datetime in an overlay
ion-input-otp One-time-passcode (segmented) input
ion-input-password-toggle Show/hide toggle for password inputs
ion-segment / ion-segment-button Segmented control
ion-segment-view / ion-segment-content Swipeable content panes tied to a segment
ion-picker / ion-picker-column / ion-picker-column-option Wheel-style picker and columns
ion-picker-legacy / ion-picker-legacy-column Deprecated legacy picker (kept for back-compat)
<ion-list>
  <ion-item>
    <ion-input label="Email" type="email" placeholder="[email removed]"></ion-input>
  </ion-item>
  <ion-item>
    <ion-toggle>Enable notifications</ion-toggle>
  </ion-item>
  <ion-item>
    <ion-select label="Fruit" placeholder="Pick one">
      <ion-select-option value="apple">Apple</ion-select-option>
      <ion-select-option value="banana">Banana</ion-select-option>
    </ion-select>
  </ion-item>
</ion-list>

Tip

In Angular, Ionic form controls integrate with both template-driven and reactive forms through built-in control value accessors — bind with [(ngModel)] or formControlName exactly as you would with native inputs. No extra setup is required beyond importing the components.

Warning

Prefer ion-datetime and the modern ion-picker/ion-picker-column over the ion-picker-legacy family. The legacy picker is retained only for backward compatibility and may be removed in a future major version.

5.5 Lists & Items

Component Purpose
ion-list Container for rows of items
ion-list-header Header row for a list
ion-item A single row; can be tappable, contain inputs, or act as a link
ion-item-divider Visual divider/section header within a list
ion-item-group Groups items under a divider
ion-item-sliding Item that reveals options on swipe
ion-item-options / ion-item-option The swipe-revealed option container and buttons
ion-label Text label inside items and form controls
ion-note Secondary/metadata text
ion-reorder / ion-reorder-group Drag-to-reorder handle and group
ion-avatar Circular image container (for profile pictures)
ion-thumbnail Square image container
ion-badge Small count/status indicator
ion-chip Compact element for tags, contacts, or filters
ion-icon Renders an icon from the Ionicons set
ion-img Lazy-loading, viewport-aware image
<ion-list>
  <ion-item-sliding>
    <ion-item>
      <ion-avatar slot="start"><img src="avatar.png" /></ion-avatar>
      <ion-label>
        <h2>Jane Doe</h2>
        <p>Tap to view profile</p>
      </ion-label>
      <ion-badge slot="end">5</ion-badge>
    </ion-item>
    <ion-item-options side="end">
      <ion-item-option color="danger">Delete</ion-item-option>
    </ion-item-options>
  </ion-item-sliding>
</ion-list>

5.6 Cards

Component Purpose
ion-card Card container
ion-card-header Card header region
ion-card-title Card title text
ion-card-subtitle Card subtitle text
ion-card-content Card body content
<ion-card>
  <ion-card-header>
    <ion-card-subtitle>Daily</ion-card-subtitle>
    <ion-card-title>Today's Summary</ion-card-title>
  </ion-card-header>
  <ion-card-content>
    Your tasks for today are on track.
  </ion-card-content>
</ion-card>

5.7 Overlays

These can be used declaratively (as elements) or programmatically (via controllers — see §10).

Component Purpose
ion-alert Dialog with a message and buttons; can collect simple input
ion-action-sheet Sheet of actions sliding up from the bottom
ion-modal Full or partial screen modal that can host arbitrary content
ion-popover Contextual overlay anchored to an element
ion-loading Blocking spinner overlay
ion-toast Brief, non-blocking message
<ion-modal [isOpen]="isModalOpen">
  <ng-template>
    <ion-header>
      <ion-toolbar>
        <ion-title>Details</ion-title>
        <ion-buttons slot="end">
          <ion-button (click)="isModalOpen = false">Close</ion-button>
        </ion-buttons>
      </ion-toolbar>
    </ion-header>
    <ion-content class="ion-padding">Modal body</ion-content>
  </ng-template>
</ion-modal>

Tip

ion-modal supports a sheet modal mode via the breakpoints and initialBreakpoint properties, letting the modal rest at partial heights (e.g. 25%, 50%, 100%) and be dragged between them.

5.8 Progress & Feedback

Component Purpose
ion-spinner Animated loading indicator (multiple styles)
ion-progress-bar Determinate or indeterminate progress bar
ion-skeleton-text Placeholder shimmer shown while content loads
ion-refresher / ion-refresher-content Pull-to-refresh control and its visuals
ion-infinite-scroll / ion-infinite-scroll-content Load-more-on-scroll control and its visuals
<ion-content>
  <ion-refresher slot="fixed" (ionRefresh)="handleRefresh($event)">
    <ion-refresher-content></ion-refresher-content>
  </ion-refresher>

  <!-- list items here -->

  <ion-infinite-scroll (ionInfinite)="loadMore($event)">
    <ion-infinite-scroll-content></ion-infinite-scroll-content>
  </ion-infinite-scroll>
</ion-content>

5.9 Content & Disclosure

Component Purpose
ion-accordion / ion-accordion-group Expand/collapse panels
ion-text Inline text with color theming
ion-skeleton-text (also listed above) loading placeholder
<ion-accordion-group>
  <ion-accordion value="first">
    <ion-item slot="header"><ion-label>Section 1</ion-label></ion-item>
    <div slot="content" class="ion-padding">Content for section 1</div>
  </ion-accordion>
  <ion-accordion value="second">
    <ion-item slot="header"><ion-label>Section 2</ion-label></ion-item>
    <div slot="content" class="ion-padding">Content for section 2</div>
  </ion-accordion>
</ion-accordion-group>

6. Icons

Icons come from the Ionicons package, a dependency of @ionic/core. Use the <ion-icon> element with a name:

<ion-icon name="heart"></ion-icon>
<ion-icon name="logo-github" size="large"></ion-icon>

In React and Vue you typically import the specific icon and pass it to the icon prop for reliable tree-shaking and bundling:

import { IonIcon } from '@ionic/react';
import { heart } from 'ionicons/icons';

<IonIcon icon={heart} />

Tip

Importing individual icons (rather than relying on the name string) ensures only the icons you use are included in your bundle, keeping app size small.


7. Theming

Ionic theming is built on CSS custom properties (variables). You change the look of your app by overriding variables — not by fighting the components' internal styles.

7.1 Global theme variables

Ionic apps include a theme/variables.css (or .scss) file. The global color palette is defined there:

:root {
  --ion-color-primary: #3880ff;
  --ion-color-primary-rgb: 56, 128, 255;
  --ion-color-primary-contrast: #ffffff;
  --ion-color-primary-shade: #3171e0;
  --ion-color-primary-tint: #4c8dff;
  /* secondary, tertiary, success, warning, danger, light, medium, dark ... */
}

Every color has five paired variables: the base color, its -rgb form, a -contrast color for text drawn on it, and -shade/-tint variants for pressed/hover states.

7.2 Applying colors

Most components accept a color attribute referencing a palette name:

<ion-button color="success">Save</ion-button>
<ion-toolbar color="primary"><ion-title>Header</ion-title></ion-toolbar>
<ion-chip color="danger">Urgent</ion-chip>

7.3 Component-level variables

Individual components expose their own CSS variables for fine-grained control:

ion-button {
  --background: #6a64ff;
  --border-radius: 8px;
  --padding-top: 16px;
}

7.4 Dark mode

Ionic provides a dark palette you opt into. The common approach is to apply it based on the system preference:

@media (prefers-color-scheme: dark) {
  :root {
    /* dark palette variable overrides */
  }
}

Ionic ships ready-made dark palette stylesheets you can import (system-driven or class-toggled), so you rarely need to hand-write the full palette.

Note

Theming is intentionally CSS-first. There is no JavaScript "theme object" to configure — set CSS variables and the components respond. This keeps theming framework-agnostic and identical across Angular, React, and Vue.


8. Spacing & Utility CSS Classes

Ionic ships utility classes you can apply to any element. The most common:

Class Effect
ion-padding Adds padding on all sides
ion-padding-top / -bottom / -start / -end Directional padding
ion-margin Adds margin on all sides
ion-text-center / -start / -end / -justify Text alignment
ion-text-uppercase / -capitalize Text transforms
ion-float-start / -end Float helpers (direction-aware)
ion-hide Hides an element
ion-hide-{breakpoint}-{up|down} Responsive show/hide
<ion-content class="ion-padding ion-text-center">
  <p class="ion-margin-top">Centered, padded content</p>
</ion-content>

Tip

The -start/-end suffixes are direction-aware: they map to left/right based on the document's text direction (LTR vs RTL), so your layouts work in right-to-left languages automatically.


9. Navigation & Routing

Ionic adds animated, stack-aware transitions on top of your framework's router. The key element is <ion-router-outlet> (Angular/React) or the routing wrapper for your framework.

9.1 How Ionic routing differs

Standard web routers replace the current view. Ionic's router outlet keeps a navigation stack so that going "back" animates the previous page in from the correct direction and (where appropriate) preserves its state. This is what gives Ionic apps native-feeling forward/back transitions.

9.2 Per framework

Angular

Use the Angular Router as normal, with IonicRouteStrategy registered (see §4.1). Place <ion-router-outlet> where pages render.

React

Wrap routes in <IonReactRouter> (from @ionic/react-router) and render them inside <IonRouterOutlet>. Hash and memory variants are available as IonReactHashRouter and IonReactMemoryRouter.

Vue

Use createRouter from @ionic/vue-router (it wraps vue-router) and render pages inside <ion-router-outlet>.

9.3 Tabs

Tabbed navigation uses ion-tabs containing an ion-tab-bar of ion-tab-buttons, each pointing at a route. Each tab maintains its own navigation stack, so switching tabs and returning preserves where you were.

9.4 Programmatic navigation

In Vue, the useIonRouter() composable returns helpers for navigating with explicit direction and animation control. In Angular, inject NavController. In React, use the router hooks from react-router together with Ionic's lifecycle hooks.


10. Overlay Controllers

Beyond using overlays as elements, you can create them imperatively. @ionic/core exports a controller for each overlay type, and each framework re-exports them (Angular exposes them as injectable services):

Controller Creates
alertController ion-alert
actionSheetController ion-action-sheet
modalController ion-modal
loadingController ion-loading
popoverController ion-popover
toastController ion-toast
pickerController (legacy) ion-picker-legacy
menuController Controls ion-menu (open/close/toggle/enable)

Every overlay controller exposes the same three methods:

Method Signature Description
create create(options): Promise<HTMLElement> Builds the overlay element with the given options
dismiss dismiss(data?, role?, id?) Dismisses the top (or a specific) overlay
getTop getTop(): Promise<HTMLElement | undefined> Returns the topmost overlay of that type
import { toastController } from '@ionic/core';

async function showToast() {
  const toast = await toastController.create({
    message: 'Saved successfully',
    duration: 2000,
    position: 'bottom',
  });
  await toast.present();
}

Important

create() only builds the overlay — you must call .present() on the returned element to show it. Use await overlay.onDidDismiss() to receive the data and role passed to dismiss().

// React / vanilla example
const alert = await alertController.create({
  header: 'Confirm',
  message: 'Delete this item?',
  buttons: [
    { text: 'Cancel', role: 'cancel' },
    { text: 'Delete', role: 'destructive' },
  ],
});
await alert.present();
const { role } = await alert.onDidDismiss();

The menuController differs slightly — it controls existing <ion-menu> elements:

import { menuController } from '@ionic/core';

await menuController.open();        // open the menu
await menuController.close();       // close it
await menuController.toggle();      // toggle it
await menuController.enable(true);  // enable/disable

11. Animations

Ionic includes a framework-agnostic animation utility, createAnimation, built on the Web Animations API. It produces a chainable Animation object.

import { createAnimation } from '@ionic/core';

const animation = createAnimation()
  .addElement(document.querySelector('.box')!)
  .duration(1500)
  .iterations(Infinity)
  .fromTo('transform', 'translateX(0px)', 'translateX(100px)')
  .fromTo('opacity', '1', '0.5');

await animation.play();

11.1 Key methods

Category Methods
Targets addElement(el), addAnimation(animations) (group child animations)
Timing duration(ms), delay(ms), iterations(n), direction(dir), easing(fn), fill(mode)
Properties from(prop, val), to(prop, val), fromTo(prop, from, to), keyframes(frames)
Playback play(opts?), pause(), stop(), destroy(), isRunning()
Progress progressStart(forceLinear?, step?), progressStep(step), progressEnd(playTo, step, dur?)
Hooks onFinish(cb, opts?), beforeStyles(), beforeAddClass(), afterStyles(), afterAddClass(), afterClearStyles()

Tip

Group animations with addAnimation() to run several element animations as one coordinated timeline:

const parent = createAnimation().duration(1000).addAnimation([animA, animB]);
await parent.play();

11.2 Replacing component transitions

Because overlay enter/leave and navigation transitions are themselves createAnimation builders, you can supply your own. Set enterAnimation/leaveAnimation on an overlay, or override globally via configuration keys like modalEnter, modalLeave, and navAnimation (see §13).


12. Gestures

createGesture provides normalized, performant pointer/touch gesture handling.

import { createGesture } from '@ionic/core';

const gesture = createGesture({
  el: document.querySelector('.draggable')!,
  gestureName: 'drag',
  direction: 'x',
  onMove: (detail) => {
    console.log('moved', detail.deltaX);
  },
});

gesture.enable();

12.1 Gesture configuration

Option Type Purpose
el Node Element the gesture is attached to (required)
gestureName string Unique name (required)
direction 'x' | 'y' Axis to track
threshold number Movement before the gesture starts
gesturePriority number Higher priority wins when gestures overlap
passive boolean Whether listeners are passive
maxAngle number Maximum angle deviation allowed
disableScroll boolean Block scrolling during the gesture
blurOnStart boolean Blur the active element when the gesture starts
canStart callback Decide whether the gesture may begin
onWillStart callback Async hook before start
onStart / onMove / onEnd callbacks Lifecycle callbacks receiving GestureDetail
notCaptured callback Fires when the gesture is not captured

Note

The GestureDetail passed to callbacks includes the current/start coordinates, deltas, velocity, and the originating event — everything needed to build swipe, drag, and pinch interactions.


13. Configuration

Ionic behavior is tuned through a single configuration object of type IonicConfig. You provide it once at startup:

  • Angular: provideIonicAngular({ ... }) or IonicModule.forRoot({ ... })
  • React: setupIonicReact({ ... })
  • Vue: app.use(IonicVue, { ... })

13.1 Common configuration keys

Key Type Effect
mode 'ios' | 'md' Force a single design mode app-wide
animated boolean Set false to disable all animations/transitions (useful on slow devices)
rippleEffect boolean Enable/disable Material ripple effects (default true)
hardwareBackButton boolean Respond to Android hardware back button (default true on mobile)
statusTap boolean Tapping the status bar scrolls to top (default true on mobile)
swipeBackEnabled boolean Enable iOS swipe-to-go-back across all ion-nav
backButtonText string Default text for all ion-back-button
backButtonIcon string Default icon for all ion-back-button
backButtonDefaultHref string Default fallback href for back buttons
menuIcon string Default icon for all ion-menu-button
menuType string Default menu animation type
spinner SpinnerTypes Default spinner for ion-spinner
loadingSpinner SpinnerTypes | null Default spinner for loading overlays
refreshingSpinner SpinnerTypes | null Default spinner for refreshers
infiniteLoadingSpinner SpinnerTypes | null Default spinner for infinite scroll
toggleOnOffLabels boolean Default on/off labels for ion-toggle
tabButtonLayout TabButtonLayout Default layout of tab buttons
toastDuration number Default duration for ion-toast
logLevel 'OFF' | 'ERROR' | 'WARN' Framework logging verbosity

13.2 Animation override keys

You can replace any default overlay or navigation animation globally:

navAnimation, actionSheetEnter/actionSheetLeave, alertEnter/alertLeave, loadingEnter/loadingLeave, modalEnter/modalLeave, popoverEnter/popoverLeave, toastEnter/toastLeave, pickerEnter/pickerLeave — each takes an AnimationBuilder.

13.3 Security keys

Key Type Effect
sanitizerEnabled boolean Enable Ionic's basic DOM sanitizer on properties that accept custom HTML
innerHTMLTemplatesEnabled boolean Allow custom HTML via innerHTML in components like ion-alert, ion-toast, ion-loading, ion-infinite-scroll-content, ion-refresher-content. Disabled by default.

Caution

innerHTMLTemplatesEnabled is false by default for security. Only enable it if you fully control and trust the HTML you pass into those components — enabling it on untrusted content opens an XSS vector. See the Admin Guide's security section.

13.4 Experimental keys

Key Type Effect
focusManagerPriority ('content' | 'heading' | 'banner')[] Move focus to the chosen element after each page transition (accessibility)
experimentalCloseWatcher boolean Use the CloseWatcher API for Escape/back-button dismissal (requires hardwareBackButton: true)

13.5 Configuration via URL and persistence

Beyond code, Ionic reads configuration from the URL query string using the ionic: prefix, which is invaluable for testing modes without code changes:

https://localhost:8100/?ionic:mode=ios&ionic:animated=false

Setting persistConfig: true saves the active configuration to sessionStorage (under the key ionic-persist-config) so URL-driven overrides survive navigation within the session.

Tip

Use ?ionic:mode=ios during development to instantly preview how your app looks in the other design mode without changing any code.


14. Page Lifecycle Events

Ionic pages fire lifecycle events as they enter and leave the navigation stack. These are distinct from your framework's own component lifecycle and fire on page transitions.

Event Fires
ionViewWillEnter Before the page becomes the active view
ionViewDidEnter After the page has fully transitioned in
ionViewWillLeave Before the page transitions away
ionViewDidLeave After the page has fully transitioned away
ionViewWillUnload Before a page is destroyed/removed

How you subscribe depends on the framework:

Angular

Implement the interfaces ViewWillEnter, ViewDidEnter, ViewWillLeave, ViewDidLeave and define the matching methods (ionViewWillEnter(), etc.).

React

Use the hooks exported by @ionic/react: useIonViewWillEnter, useIonViewDidEnter, useIonViewWillLeave, useIonViewDidLeave.

Vue

Use the composables from @ionic/vue: onIonViewWillEnter, onIonViewDidEnter, onIonViewWillLeave, onIonViewDidLeave.

Note

These events are what make caching navigation behave correctly: a cached page that is revisited fires ionViewWillEnter/ionViewDidEnter again without re-running its constructor, so you refresh data in these hooks rather than in the framework's "created" hook.


15. Platform Utilities

Detect the runtime environment to branch behavior:

import { isPlatform, getPlatforms } from '@ionic/core';

if (isPlatform('ios')) {
  // iOS-specific logic
}

console.log(getPlatforms()); // e.g. ['ios', 'mobile', 'mobileweb', 'phablet']

isPlatform(name) returns true for platform identifiers such as ios, android, ipad, iphone, phablet, tablet, mobile, desktop, and pwa. getPlatforms() returns the full array of matching platforms. In Angular, the injectable Platform service offers the same checks plus observables for ready/resume/pause events.

The mode (ios/md) is independent of platform — getMode() tells you which design language is active, while isPlatform() tells you which device you're running on.


16. Vue & React Hooks Reference

Beyond lifecycle hooks, the framework packages export convenience hooks.

Vue (@ionic/vue):

Hook Returns
useBackButton() Register handlers for the hardware/Escape back button
useKeyboard() Reactive keyboard open state and height
useIonRouter() Programmatic navigation with direction/animation control

React (@ionic/react): the lifecycle hooks above, plus context (NavContext, IonLifeCycleContext) and generateId utilities used internally by routing.


17. Building for Native (Capacitor)

Ionic UI runs in a web layer; Capacitor packages that web app as a native iOS/Android binary and bridges to native device APIs.

npm install @capacitor/core @capacitor/cli
npx cap init
npx cap add ios
npx cap add android
npm run build          # produce your web build
npx cap sync           # copy web assets + plugins into native projects
npx cap open ios       # open in Xcode

Note

Ionic's components automatically integrate with Capacitor plugins where relevant — for example, @ionic/core lists @capacitor/keyboard, @capacitor/haptics, and @capacitor/status-bar so that inputs adjust for the on-screen keyboard, controls give haptic feedback, and the status bar is handled correctly on device.


18. Troubleshooting

Entries below are drawn from the framework's own error messages and community-reported issues.

Error: framework delegate is missing

Cause: An overlay that hosts user-supplied components (ion-modal, ion-popover, ion-nav) was used without the framework's delegate being available — usually because the Ionic provider/plugin was not initialized, or a core overlay is being used in a framework context without the wrapper. Solution: Ensure you initialized Ionic for your framework (provideIonicAngular()/IonicModule.forRoot(), setupIonicReact(), or app.use(IonicVue)) and that you import the modal/popover from the framework package, not directly from @ionic/core. Prevention: Always use the @ionic/{angular,react,vue} wrappers for component-hosting overlays.

Error: Invalid hour cycle

Cause: ion-datetime received an hourCycle value it does not recognize. Solution: Use a valid hourCycle (h11, h12, h23, or h24) or omit it to let the locale decide. Prevention: Bind hourCycle to a constrained set of values.

Error: TS2320: Interface 'HTMLIonInputElement' cannot simultaneously extend types ...

Cause: A TypeScript type conflict between the generated element interface and Stencil's base element interface — typically a type-version mismatch (community issue #30650). Solution: Align your TypeScript and @ionic/core versions, clear node_modules, and reinstall. Ensure only one copy of @ionic/core types resolves. Prevention: Keep @ionic/core and framework wrapper versions in lockstep (they share the same version number).

Problem: ion-datetime-button not rendering inside a modal

Cause: Reported in community issues #30504 and #31155 — the datetime overlay binding can fail to associate when the button and the ion-datetime it controls are in different overlay contexts. Solution: Ensure the ion-datetime referenced by the button's datetime property exists in the same presented overlay and that its id matches. Present the datetime within the same modal as the button. Prevention: Keep ion-datetime-button and its target ion-datetime in the same template/overlay.

Problem: ion-modal does not show content with auto height

Cause: Community issue #31149 — a modal with auto-sizing content can collapse if the content has no intrinsic height. Solution: Give the modal content an explicit height or use the breakpoints/initialBreakpoint sheet-modal API instead of relying on auto height. Prevention: Prefer explicit sizing for modals whose content height is dynamic.

Problem: React Router <Switch> breaks passing state as child props

Cause: Community issue #31157 — interaction between @ionic/react-router and react-router's <Switch> when passing state through child props. Solution: Pass route state through route params or context rather than as child props under <Switch>; verify your react-router version matches what @ionic/react-router expects. Prevention: Follow the routing patterns generated by ionic start for React.

Warning: deprecated host-context pseudo-class when compiling with Lightning CSS

Cause: Community issue #30024 — Ionic's CSS emits :host-context(), which Lightning CSS flags as deprecated. Solution: These are warnings, not errors; the app still works. If your build treats warnings as errors, configure your CSS pipeline to allow :host-context. Prevention: Track the issue for a framework-side fix in a future release.

Problem: spurious page transitions on routes with query params

Cause: Community issue #31152 — IonRouter.handleHistoryChange can compare a search-bearing URL to a search-free path, triggering extra transitions on popstate. Solution: Be cautious mixing query-string state with Ionic navigation; where possible, encode state in path params. Prevention: Minimize query-param-driven navigation within Ionic outlets until the fix lands.


19. Frequently Asked Questions

Q: Do I have to choose Angular, React, or Vue? Yes — pick the framework you know. The components and APIs are identical; only the import names and binding syntax differ. You can also use @ionic/core directly with no framework.

Q: Is this the same as the old ionic-angular package? No. ionic-angular was Ionic 3 and lives in the archived ionic-team/ionic-v3 repository. Modern Ionic (v4+) is framework-agnostic Web Components with the @ionic/* packages documented here.

Q: What is the difference between Ionic and Capacitor? Ionic is the UI framework (the components and APIs in this guide). Capacitor is the native runtime that wraps your web app into an iOS/Android app and exposes device APIs. They are designed to work together but are separate projects.

Q: How do I change my app's colors? Override the --ion-color-* CSS variables in your theme file. See §7 Theming.

Q: How do I force iOS styling everywhere? Set mode: 'ios' in your Ionic configuration, or append ?ionic:mode=ios to the URL while testing. See §13.

Q: My animations are janky on low-end devices. What can I do? Set animated: false in configuration to disable transitions globally, or rippleEffect: false to drop Material ripples.

Q: Can I use my own animations for modals and page transitions? Yes. Supply an AnimationBuilder via the per-overlay enterAnimation/leaveAnimation props or globally via config keys like modalEnter/modalLeave/navAnimation. See §11.2.

Q: Why does my page not run its constructor when I navigate back to it? Ionic caches pages in the navigation stack. Use the ionViewWillEnter/ionViewDidEnter lifecycle events to refresh data on revisit. See §14.

Q: How do I show a quick message? Use a toast — declaratively with <ion-toast> or programmatically with toastController.create({ message, duration }). See §10.

Q: Can I use Ionic components without a build step? Yes — load @ionic/core from a CDN and use the ion-* elements directly in HTML. The framework wrappers exist to improve the developer experience in Angular/React/Vue, but they are optional.

Q: How do I make my app work in right-to-left languages? Use Ionic's direction-aware slot="start"/slot="end" and ion-padding-start/-end utilities (rather than left/right), and set the document dir="rtl". Components flip automatically.

Q: Which Angular versions are supported? Angular 16 and above (peer requirement @angular/core >=16.0.0). Support for the newest Angular majors is added over time; check the issue tracker before adopting a brand-new Angular release.