Routing
A single-page application still needs "pages": a home page, a menu, an about page, an account area. The Angular Router maps each URL to a component and swaps components inside the page as the user navigates, without reloading. The browser's back and forward buttons and bookmarks keep working.
In this lesson you will define routes, show them, link between them and navigate from code. The next lesson adds route parameters, guards and lazy loading.
Define your routes
A new project already has src/app/app.routes.ts and calls provideRouter(routes) in app.config.ts. A route is an object with at least a path and a component:
import { Routes } from '@angular/router';
import { Home } from './home/home';
import { MenuPage } from './menu-page/menu-page';
import { About } from './about/about';
import { NotFound } from './not-found/not-found';
export const routes: Routes = [
{ path: '', component: Home, title: 'Campus Canteen' },
{ path: 'menu', component: MenuPage, title: 'Menu | Campus Canteen' },
{ path: 'about', component: About, title: 'About | Campus Canteen' },
{ path: 'home', redirectTo: '', pathMatch: 'full' },
{ path: '**', component: NotFound, title: 'Not found' },
];pathis the part of the URL after the domain, without a leading slash.''is the home page.titlesets the browser tab title when the route is active, which also helps accessibility.redirectTosends one URL to another.pathMatch: 'full'means "only when the whole URL matches", which you need for redirects from''or short paths.'**'is the wildcard route. It matches anything not matched earlier, so it is your 404 page.
The router checks routes in order and uses the first match. Always put the wildcard last; anything after it can never match.
Show routes with router-outlet
<router-outlet /> marks where the active route's component appears. Put it in the root component, around which you place things that stay on every page, such as a navigation bar:
import { Component } from '@angular/core';
import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
imports: [RouterOutlet, RouterLink, RouterLinkActive],
template: `
<nav>
<a routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">Home</a>
<a routerLink="/menu" routerLinkActive="active">Menu</a>
<a routerLink="/about" routerLinkActive="active">About</a>
</nav>
<main>
<router-outlet />
</main>
`,
styles: `
.active {
font-weight: bold;
border-bottom: 2px solid #c3002f;
}
`,
})
export class App {}Visiting http://localhost:4200/menu shows the navigation bar, then the MenuPage component inside <main>, and the tab title becomes "Menu | Campus Canteen". Visiting /xyz shows the not-found page.
Links with routerLink
Use routerLink instead of href for links inside your app:
href="/menu"makes the browser download the whole app again: a full page reload that loses all signals and state.routerLink="/menu"lets the router change the URL and swap the component instantly.
For URLs built from data, bind an array of path segments: [routerLink]="['/orders', order.id]" produces /orders/104.
routerLinkActive="active" adds the active CSS class to the link while its route is showing, so users can see where they are. Because / is the start of every URL, the Home link needs [routerLinkActiveOptions]="{ exact: true }", or it would look active on every page.
Navigating from code
Sometimes you navigate after an action, for example after an order is placed. Inject the Router and call navigate() with path segments, or navigateByUrl() with a full URL string:
import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-about',
template: `
<h2>About us</h2>
<button (click)="goToMenu()">See the menu</button>
`,
})
export class About {
private router = inject(Router);
protected goToMenu() {
this.router.navigate(['/menu']);
}
}Both methods return a promise that resolves to true when navigation succeeds. Use links for normal navigation (they work with right-click, "open in new tab" and screen readers), and code navigation only after actions.
Nested routes
A section of the app can have its own sub-pages. Give a route children and put a second <router-outlet /> in that route's component:
{
path: 'account',
component: Account,
children: [
{ path: '', redirectTo: 'profile', pathMatch: 'full' },
{ path: 'profile', component: Profile },
{ path: 'orders', component: PastOrders },
],
},The Account template contains its own small menu with relative links (routerLink="profile", no leading slash) and a <router-outlet />. Visiting /account redirects to /account/profile:
My account Profile | Past orders Name: Priya Sharma
The outer outlet shows Account, and the inner outlet shows Profile.
Deploying: the server must know about routes
During development, ng serve handles every URL. On a real server, a user may open https://example.com/menu directly or press refresh. The server looks for a file called menu, finds nothing and returns a 404 error. The fix is to tell the server to send index.html for any URL that is not a real file, so Angular can read the URL and show the right page. For Apache (as in XAMPP), a .htaccess file next to index.html can do this:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [L]Other servers (Nginx, Firebase Hosting, Netlify) have their own "fallback to index.html" setting.
Common mistakes
- A leading slash in
path. Writepath: 'menu', notpath: '/menu'; the router reports an error for the slash. - The wildcard route not last. Routes after
'**'are never reached. - Using
hreffor internal links. It reloads the whole app. UserouterLink. - Forgetting to import
RouterLink. Without it,routerLinkis just an unknown attribute and clicking does nothing useful. ImportRouterLink,RouterLinkActiveandRouterOutletwhere you use them.
Key points
- Routes in
app.routes.tsmap paths to components;provideRouter(routes)turns routing on. <router-outlet />shows the active route's component; nested routes use nested outlets.- Use
routerLinkfor links,routerLinkActiveto highlight the current page, andRouter.navigate()from code. redirectTowithpathMatch: 'full'handles redirects;'**'catches unknown URLs and must be last.- On a real server, configure a fallback to
index.htmlso deep links and refreshes work.
Exercise
Add routing to a school website with three pages: Home (''), Admissions (admissions) and Contact (contact), each with its own tab title. Add a not-found page. In the root component, create a navigation bar with active-link highlighting. On the Contact page, add a button "Apply now" that navigates to Admissions from code.
Show solution
export const routes: Routes = [
{ path: '', component: SchoolHome, title: 'Sunrise Public School, Rohtak' },
{ path: 'admissions', component: Admissions, title: 'Admissions | Sunrise Public School' },
{ path: 'contact', component: Contact, title: 'Contact | Sunrise Public School' },
{ path: '**', component: NotFound, title: 'Page not found' },
];
@Component({
selector: 'app-contact',
template: `
<h2>Contact us</h2>
<p>Phone: 01262-000000</p>
<button (click)="apply()">Apply now</button>
`,
})
export class Contact {
private router = inject(Router);
protected apply() {
this.router.navigate(['/admissions']);
}
}The root template contains three <a routerLink=... routerLinkActive="active"> links (with exact: true on Home) and a <router-outlet />. The wildcard route is last so that only unknown URLs reach the not-found page.
Quick Quiz
1. Where does the router display the component for the current URL?
The outlet is the placeholder the router fills with the active route's component.
2. Why use routerLink instead of href for links inside the app?
A normal href triggers a full page load and loses the app's state.
3. What does the path '**' match?
The wildcard route is used for 404 pages and must come last.
4. A user refreshes /menu on your Apache server and gets a 404. What is the fix?
The server must hand every app URL to index.html so Angular's router can handle it.
Learn Angular with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
