Mapping Out the Navigation Layout
We'll assemble a navigation structure with several layers, similar to what an e-commerce site or a learning platform might use.
Bootstrap will provide the styling foundation for the menu system we're about to construct.
This is a hands-on walkthrough: the focus is on configuring the Angular Router through a real, working example. We'll cover the core routing scenarios that show up again and again in production applications.
What We'll Cover
These routing features will be combined to build the complete menu system:
- Initial Router Setup
- Child Routes
- Nested Child Routes
- Auxiliary Routes
- Nested Auxiliary Routes
This is the second installment in our series on the Angular Router. The full series includes:
Angular Router Fundamentals: Child Routes, Auxiliary Routes, Master-Detail
Angular Router: A Complete Guide (with Bootstrap)
Let's move on to building the navigation menu.
The Target Design
Here's a visual of the menu system we're aiming for:

The layout contains these pieces:
- a persistent top-level menu
- a trail of breadcrumbs for navigation context
- A secondary sidebar that appears only after the
Coursessection is entered - navigation between the course category listing and each individual category, with the sidebar contents updating accordingly
Building the Top Menu
Because the top menu needs to be present at all times, it belongs in the application's root component. Every view will render below it.
Alternatively, the menu markup can live in a dedicated top-menu.component.ts file, which is useful if the menu grows large. Note the routerLink directives that point to home, about, and courses.
The router-outlet element is the key: whatever page we're on, its main content gets injected right there. When we start, nothing occupies the sidebar space—it should only exist when the Courses link is activated. Next, we define the router config for this top-level navigation.
Top Menu Router Configuration
This starting config handles all the routes the top menu exposes:
The home, about, and courses paths each map to a single component. There's also a redirect handling the root path (empty string) and a catch-all with the ** wildcard for unmatched URLs.
This initial setup already covers the home page, gracefully handles bad URLs, and lays down the main navigation items.
With the header in place, these are next on the list:
- a sidebar that lists the course categories, shown only when
Coursesis selected - a set of category cards appearing in the page's main content area
The Courses Categories View
This is what CoursesComponent should render:

The screen is made up of a few distinct parts:
- a large 'jumbotron' heading that reads "Course Categories!"
- a grid of course category cards, three per row
- a sidebar with navigation shortcuts to each category
The content under the top menu fills the router outlet, as expected. This view, however, has its own internal routing logic we'll need to manage.
Adding the Sidebar
To support the sidebar, CoursesComponent needs to provide its own outlets:
- a primary outlet inside the component to display the list of course categories
- an auxiliary outlet to host the sidebar navigation
Before getting into the details, we need to use Child Routes. A solid introduction to child routes is available in this earlier post.
Let's look at this routing scenario in more detail.
Nested Route for the Category Cards
In the CoursesComponent template, the implementation looks like this:
Notice the multiple router-outlet elements: this component itself is loaded inside a top-level outlet, yet defines its own outlets. This is the nested route pattern.
We'll get to the auxiliary outlet shortly. For now, our aim is to configure the router so the category cards component populates the unnamed outlet.
Nested Route Configuration
The router config needed to load both the courses view and the category cards is as follows:
Navigating to /courses triggers this behavior:
CoursesComponentis rendered inside the mainrouter-outletlocated below the top menu- Within
CoursesComponent, the<router-outlet></router-outlet>gets replaced byCourseCardsComponent
This is progress, yet the sidebar remains. To populate it, we'll rely on the auxiliary route concept.
Secondary Routes in Practice
When different sections of the screen change independently based on the URL, we are dealing with secondary (or auxiliary) routes. In the router configuration, this translates to a route that uses an outlet name other than the default one.
The main route is tied to the unnamed outlet (<router-outlet></router-outlet>). Beyond that, a single routing level can host any number of additional outlets, provided each one carries a distinct name.
Building the Side Menu Component
We'll place the side menu inside a sidemenu-named outlet. The menu's links should adapt based on the current URL. For instance, landing on the Courses section should show a list of Course Categories, but drilling into a specific category should display sub-category links.
To pull this off, the SideMenuComponent needs access to the current URL to decide which data to load. The example below is a stripped-down version; in a real scenario you'd inject a service or use a Router Resolver to fetch data before the component initializes.
More importantly, note how the side menu listens for URL changes—this reactivity is what makes it flexible enough to mirror the main content.
Setting Up a Nested Secondary Route for the Menu
Here's a router configuration that mounts the side menu:
Navigating to /courses will now yield the following results for the courses.component.html template:
- The
CourseCardsComponentfills the default (primary)router-outlet. - The
SideMenuComponentappears inside the outlet labeledsidemenu.
A pattern starts to emerge: the router handles a wide array of navigation contexts using just a few core concepts: routes, outlets, and child routes.
We can push this pattern further by adding another layer of navigation.
Creating the Course Categories Component
Suppose the user clicks on Development while inside the Courses area. We want two things to happen simultaneously:
-
The primary outlet inside Courses swaps its content for a new component that shows the category's contents, such as a list of sub-categories.
-
The side menu also updates to display links specific to the
Developmentcategory.
While the URL changes, two separate regions on the page react independently.
One More Level of Nesting
If the user clicks Development, the URL shifts to /courses/development. A click on IT & Software would change it to /courses/it-software, and so on.
For these URLs, we'll display a fresh CoursesCategoryComponent in the primary outlet of the Courses page. The configuration for that looks like this:
Note the :id placeholder—it captures the dynamic segment of the URL, resulting in values like development or it-software.
Drilling into a Sub-Section
To fetch data for a particular category, the Development card can trigger a navigation like this:
Right away, you'll notice a limitation: this navigation won't inform the side menu about the change—more on that below.
While the main body would correctly render CoursesCategoryComponent, the side menu wouldn't budge.
Adapting the Side Menu to the URL
In our current setup, the side menu initializes when the user enters the Courses page via the top menu and then stays static. To ensure it reacts to the category-specific URL—for example by showing development sub-sections—the router configuration needs another piece:
We've now added a navigation route for the side menu outlet too. When the browser lands on /courses/development, we'd anticipate the SideMenuComponent picking up the development segment via a subscription to its params observable.
Alas, that's not how it works—let's dig into why.
A Side Menu's Perspective
From the side menu's viewpoint, navigating from /courses to /courses/development only changes the primary route. Content inside the sidemenu outlet remains untouched.
To get the side menu to change, a separate navigation within the sidemenu outlet is required. Think of it as having two parallel browser windows on the same page: one drives the main content, the other drives the side menu.
Triggering Side Menu Navigation
To initiate a navigation for the side menu, we might still do it from the template—but for complicated navigation, we can inject the router and use its imperative navigation API.
Template-based navigation is fine, but leveraging TypeScript auto-completion when calling the router's methods can be a lifesaver. It effectively serves as a real-time documentation, suggesting the valid parameters as you type.
To get started, we'll swap the routerLink directive on the category card for a click handler:
Now the navigation is fired via a method call, not directly in the markup. Let's look at that method.
Navigating Multiple Outlets Programmatically
Here is how we can pull off the navigation in code, which could also be recreated in the template using router commands:
Notice we're issuing one router navigation command that targets two outlets at once: the primary and the sidemenu.
Here is what happens in each one:
-
Because we provide a
relativeToproperty with the current active route, the navigation is relative to the route we're already on. -
The primary outlet's navigation path (
/courses/development) loadsCoursesCategoryComponentinto the main Courses template. -
The auxiliary
sidemenuoutlet's navigation (via the same path) allows theSideMenuComponentto refresh based on the new segment.
Since the SideMenuComponent is subscribed to the route.params observable, the click on the Development card will now cause development to be written to the console via console.log.
Now that the side menu is notified of URL transitions, it can dynamically swap its content when needed.
What a Multi-Outlet URL Looks Like
If you preview your browser's address bar after triggering the nav call above, you'd see:
/courses/(development//sidemenu:development)
To break that URL down:
- the courses segment is currently active
- within it, the primary route points to
/courses/development - the auxiliary route for
sidemenuis set to thedevelopmentchild segment
Final Takeaways
The Angular router's configuration API is remarkably lean but versatile. With a handful of building blocks—routes, outlets, and child routes—we can support a broad range of situations.
Interestingly, a lot of typical navigation ideas (like 'nested routes') don't map 1:1 to any single term in the router's configuration. A nested view might simply be a child route with a different component; likewise, an auxiliary route is just a standard route assigned to a named outlet, inheriting all the properties of a primary route.
Starting from these primitive concepts, it's easy to arrange most navigation flows an app might need: top-level menus, hierarchical pages, sidebars, and more.
We hope this guiding walkthrough of the Angular Router Table proves helpful--happy navigating!
Questions or feedback? Drop them in the comments below and we'll jump in.
Want to catch upcoming posts on the Angular Router and related topics? Subscribe to our newsletter:
To go much deeper into all the Angular Router's advanced capabilities, check out the Angular Router In Depth course for exhaustive detail.
Getting started with Angular and looking for a foundation course? See the Angular for Beginners Course:
Further Reading on Angular
If you found this article useful, you might also like these popular posts:
- Angular Router - Extended Guided Tour, Avoid Common Pitfalls
- Angular Components - The Fundamentals
- How to build Angular apps using Observable Data Services - Pitfalls to avoid
- Introduction to Angular Forms - Template Driven vs Model Driven
- Angular ngFor - Learn all Features including trackBy, why is it not only for Arrays ?
- Angular Universal In Practice - How to build SEO Friendly Single Page Apps with Angular
- How does Angular Change Detection Really Work?
- Typescript 2 Type Definitions Crash Course - Types and Npm, how are they linked ? @types, Compiler Opt-In Types: When To Use Each and Why ?
