Navigation Patterns
Ionic uses your framework’s router (Angular Router, React Router, Vue Router) under the hood, with IonRouterOutlet handling native-feeling stack transitions and back gestures.
Angular + React routing with IonRouterOutlet
EXAMPLE
// === Angular (Ionic + Angular Router) ===
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', loadComponent: () => import('./home/home.page').then(m => m.HomePage) },
{ path: 'post/:id', loadComponent: () => import('./post/post.page').then(m => m.PostPage) },
{ path: 'tabs',
loadComponent: () => import('./tabs/tabs.page').then(m => m.TabsPage),
children: [
{ path: '', redirectTo: 'feed', pathMatch: 'full' },
{ path: 'feed', loadComponent: () => import('./feed/feed.page').then(m => m.FeedPage) },
{ path: 'profile', loadComponent: () => import('./profile/profile.page').then(m => m.ProfilePage) },
],
},
{ path: 'login', loadComponent: () => import('./login/login.page').then(m => m.LoginPage) },
{ path: '**', loadComponent: () => import('./not-found/not-found.page').then(m => m.NotFoundPage) },
];
@NgModule({
imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })],
exports: [RouterModule],
})
export class AppRoutingModule {}
// app.component.html
// <ion-app>
// <ion-router-outlet></ion-router-outlet>
// </ion-app>
// Inside a page — navigate programmatically
import { NavController } from '@ionic/angular';
@Component({ /* … */ })
export class HomePage {
constructor(private nav: NavController) {}
open(id: string) {
this.nav.navigateForward(`/post/${id}`, { animated: true });
}
back() {
this.nav.navigateBack('/home');
}
}
// Read route params
import { ActivatedRoute } from '@angular/router';
constructor(private route: ActivatedRoute) {
this.id = this.route.snapshot.paramMap.get('id')!;
}
// === React (Ionic React) ===
import { IonReactRouter } from '@ionic/react-router';
import { IonApp, IonRouterOutlet, IonTabs, IonTabBar, IonTabButton } from '@ionic/react';
import { Route, Redirect } from 'react-router-dom';
export default function App() {
return (
<IonApp>
<IonReactRouter>
<IonRouterOutlet>
<Route exact path="/home" component={HomePage} />
<Route path="/post/:id" component={PostPage} />
<Route path="/tabs" component={TabsPage} />
<Route exact path="/" render={() => <Redirect to="/home" />} />
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
);
}
// useHistory / useParams
import { useHistory, useParams } from 'react-router-dom';
function PostPage() {
const history = useHistory();
const { id } = useParams<{ id: string }>();
return <IonButton onClick={() => history.push('/home')}>Back</IonButton>;
}
// === Tabs (Angular) ===
// tabs.page.html
// <ion-tabs>
// <ion-tab-bar slot="bottom">
// <ion-tab-button tab="feed" href="/tabs/feed"> <ion-icon name="home"/></ion-tab-button>
// <ion-tab-button tab="profile" href="/tabs/profile"><ion-icon name="person"/></ion-tab-button>
// </ion-tab-bar>
// </ion-tabs>
// === Common gotchas ===
// • Use ion-router-outlet at the ROOT, not just <router-outlet> — keeps native gestures
// • Tabs need IonTabs around IonTabBar AND IonRouterOutlet — both required
// • Back-button behaviour — set defaultHref on ion-back-button to handle deep links
Why it matters
IonRouterOutlet is what gives Ionic apps native-feeling page transitions and swipe-back gestures. A vanilla <router-outlet> won’t cut it — the framework-specific wrapper is mandatory.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Push a new page
nav.push(ProfilePage);
// Or with React Router
history.push('/profile/42');
Try it Yourself »
Discussion
Loading…