In Angular route definitions, what do the title and data properties do, and which title wins when routes are nested?
answer
- the document title changes on navigation
- static string or ResolveFn
- deepest primary route wins
- untitled routes keep the old title
- data is static metadata
basics
~20 stitle sets the document title when the route activates, as a string or a ResolveFn; with nesting, the deepest title on the primary outlet path wins. data attaches static metadata, such as an analytics id.
solid answer
~40 s`title` on a `Route` is either a string or a resolver (`ResolveFn<string>` or a class) that computes one, for example from a post's slug. After a successful navigation, the default `TitleStrategy` walks the primary outlet path from the root to the deepest route and uses the last title it finds, then sets it with the `Title` service. If no route on that path has a title, it leaves the document title unchanged, so the previous page's title can linger. `data` is an object of static values — breadcrumbs labels, analytics ids, feature flags — that components, guards or strategies read from the route snapshot. It is not for fetched data: that is what resolvers and route resources are for.
code
ts · 15 linesimport { inject } from '@angular/core';
import { ResolveFn, Routes } from '@angular/router';
import { PostList } from './posts/post-list';
import { PostDetail } from './posts/post-detail';
import { PostHeadlines } from './posts/post-headlines';
import { NotFound } from './not-found';
const postTitle: ResolveFn<string> = (route) =>
inject(PostHeadlines).headlineFor(route.paramMap.get('slug') ?? '');
export const routes: Routes = [
{ path: 'posts', component: PostList, title: 'All posts', data: { analyticsId: 'post-list' } },
{ path: 'posts/:slug', component: PostDetail, title: postTitle, data: { analyticsId: 'post-detail' } },
{ path: '**', component: NotFound, title: 'Page not found' },
];go deeper
Recall that title sets the browser tab title and data holds static values attached to a route.
Explain string versus ResolveFn titles, the deepest-primary-route rule and what belongs in data versus a resolver.
Catch lingering titles, give every leaf a meaningful title for accessibility, and keep data limited to static configuration.
Set conventions for titles and route metadata across teams, including accessibility checks and analytics naming.
## `title`: page titles from the route table Document titles matter for accessibility — screen readers announce them after navigation — and for tabs, history and bookmarks. Angular's router can set them for you from the route table: ```ts { path: 'posts', component: PostList, title: 'All posts' } ``` The `title` property accepts: - a **string** for a fixed title; - a **`ResolveFn<string>`**, a function run like a data resolver, which can `inject()` services and return the title synchronously or asynchronously; - a class implementing `Resolve<string>` (the older, class-based form). A resolved title is computed as part of the navigation, like other resolvers, and is exposed on `ActivatedRoute.title` and on the route snapshot's `title`. ## Which title wins After the navigation completes, the router's **`TitleStrategy`** updates the document title. The default one, `DefaultTitleStrategy`: 1. starts at the root of the router state; 2. walks down the **primary outlet** children to the deepest active route; 3. remembers the last route along that path that has a title; 4. sets that value with the `Title` service from `@angular/platform-browser`. Consequences: | Configuration | Resulting document title | |---|---| | Parent `title: 'Blog'`, child `title: 'All posts'` | `All posts` (deepest wins) | | Parent `title: 'Blog'`, child without title | `Blog` | | No route on the path has a title | unchanged — whatever the previous page set | | Named outlet child with a title | ignored; only the primary outlet path is walked | The "unchanged" row is a common bug: navigating from a titled page to an untitled one keeps the old title. Give every leaf route a title, or a parent title that covers its section. Formatting every title (for example adding the site name) is done with a custom `TitleStrategy`, which belongs to router customisation. ## `data`: static route metadata `data` is an object of arbitrary key/value pairs fixed in the route table: ```ts { path: 'posts/:slug', component: PostDetail, data: { breadcrumb: 'Post', analyticsId: 'post-detail' } } ``` Typical uses: - labels for **breadcrumbs** built by walking the route tree; - **analytics** or telemetry identifiers; - flags read by a **guard** or strategy, such as required roles or a reuse hint; - layout hints read by a shell component. It is read from `ActivatedRoute.data` or the snapshot's `data`, and, when the router is configured for it, bound to component inputs. Values are static: they do not change per navigation. For per-navigation values, use a resolver (`resolve`) or a route-level resource. ## How `title` and `data` relate Internally the resolved title is stored in the route's data under a private symbol key, which is why it resolves alongside other resolved data. You do not read it from there; use `title` on the route or snapshot. ## Titles, accessibility and tests - A distinct title per page lets screen-reader users confirm that a navigation happened and where they landed; identical titles across pages remove that cue. - Put the most specific information first (the post headline before the site name) so it survives tab truncation; the ordering convention itself is a job for a custom strategy. - A route test can navigate to a URL and then read the `Title` service's `getTitle()` to assert the expected text, which catches lingering or missing titles before release. ## For the blog - `posts` gets `title: 'All posts'`. - `posts/:slug` gets a `ResolveFn<string>` that looks up the post's headline from the slug, so each article's tab shows its headline. - `**` gets `title: 'Page not found'`, so a bad URL does not keep the previous page's title. ## What interviewers listen for The two title forms, the deepest-primary-route rule, the lingering-title trap, and the distinction between static `data` and fetched data. Mentioning that titles are an accessibility requirement, not decoration, is a plus.
- Why does a page sometimes keep the previous page's title after navigation?The default `TitleStrategy` only sets the document title when some route on the primary path has a title. If the new route and its ancestors have none, it leaves the title as it was. Give every leaf, or its section parent, a title.
- Should route data hold the post fetched for /posts/:slug?No. `data` is static configuration fixed when the table is written. Data that depends on the URL and must be loaded belongs in a resolver or a route-level resource, which run per navigation.
saying these in an interview costs you the question
- The top-level parent's title overrides its children's
- A route without a title resets the tab to the index.html title
- Route data is re-fetched on every navigation
- title can only be a static string
- Titles on named outlet routes set the document title