Angular Routing Basics: Pages, RouterLink and RouterOutlet

Angular Tutorial: Beginner to Advanced · 9. Routing and navigation · 3 min read · Updated

A real app has more than one page. The Angular router watches the URL and shows the matching component, without reloading the browser. In this lesson you build a small site with Home, About and a not-found page.

What you will learn

  • How to define routes in app.routes.ts
  • How RouterOutlet and RouterLink work together
  • How to mark the active link and handle unknown URLs

Create the pages

// src/app/pages/home.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-home',
  template: `<h2>Home</h2><p>Welcome to the learning site.</p>`,
})
export class Home {}
// src/app/pages/about.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-about',
  template: `<h2>About</h2><p>This site teaches Angular step by step.</p>`,
})
export class About {}
// src/app/pages/not-found.ts
import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';

@Component({
  selector: 'app-not-found',
  imports: [RouterLink],
  template: `<h2>Page not found</h2><p><a routerLink="/">Go back home</a></p>`,
})
export class NotFound {}

Define the routes

// src/app/app.routes.ts
import { Routes } from '@angular/router';
import { Home } from './pages/home';
import { About } from './pages/about';
import { NotFound } from './pages/not-found';

export const routes: Routes = [
  { path: '', component: Home, title: 'Home' },
  { path: 'about', component: About, title: 'About' },
  { path: '**', component: NotFound, title: 'Not found' },
];

The router checks routes from top to bottom and uses the first match. That is why the ** wildcard route goes last. The title property sets the browser tab title for you.

Show the pages

// src/app/app.ts
import { Component } from '@angular/core';
import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';

@Component({
  imports: [RouterOutlet, RouterLink, RouterLinkActive],
  selector: 'app-root',
  templateUrl: './app.html',
  styleUrl: './app.css',
})
export class App {}
<!-- src/app/app.html -->
<header>
  <nav aria-label="Main">
    <a routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">Home</a>
    <a routerLink="/about" routerLinkActive="active">About</a>
  </nav>
</header>
<main>
  <router-outlet />
</main>
/* src/app/app.css */
nav { display: flex; gap: 1rem; padding: 1rem 0; }
nav a.active { font-weight: bold; text-decoration: underline; }

The app config already contains provideRouter(routes) from the project the CLI generated, so no extra setup is needed.

The key parts

  • <router-outlet /> is the placeholder where the matched page appears.
  • routerLink creates a link that changes the URL without a page reload. Use it instead of href for pages inside your app.
  • routerLinkActive="active" adds a CSS class to the link of the current page.
  • exact: true on the Home link stops it from being active on every URL, because / is the start of all of them.
  • provideRouter(routes) registers the routes for the whole app.

Try it yourself

  1. Add a /contact page with its own link in the navigation.
  2. Visit a URL that does not exist and check that the not-found page appears.
  3. Add a redirect route { path: 'home', redirectTo: '', pathMatch: 'full' } and test it.

Quick check

  1. What does RouterOutlet do?
  2. Why is the ** route placed last?
  3. Why use routerLink rather than href?

Next, learn how to read values from the URL in route parameters. The official routing guide has more detail.

Frequently asked questions

Do I need a server setting for Angular routes?

When you deploy, the web server must return index.html for unknown paths so deep links like /about work after a refresh. The deploy lesson covers this.

What is the difference between routerLink and navigate()?

routerLink is for links in templates. The Router service's navigate method is for moving to a page from code, for example after a form is saved.