SEO
Open in Document titles, meta tags, Open Graph and Twitter cards, and canonical URLs, driven by the router and built on Angular's TitleStrategy.
Prerequisites
The library reads and updates the tags that are already on the page. The canonical link in particular is only ever updated, never created. Add a static baseline to your index.html so the correct tags exist for the first paint, before Angular bootstraps.
<link rel="canonical" href="https://example.com" />
<meta name="description" content="Angular UI components built with Tailwind CSS." />
<meta name="robots" content="index, follow" />
<meta property="og:title" content="My App" />
<meta property="og:description" content="Angular UI components built with Tailwind CSS." />
<meta property="og:type" content="website" />
<meta property="og:image" content="https://example.com/assets/og/og.webp" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="My App" />
<meta name="twitter:description" content="Angular UI components built with Tailwind CSS." />
<meta name="twitter:image" content="https://example.com/assets/og/og.webp" />setCanonical() queries the existing <link rel="canonical"> and rewrites its href on every navigation, resolving relative URLs against the configured origin and stripping fragments. Without that element in index.html, there is nothing to update.
Setup
Add provideSeo to your application config. It must be registered afterprovideRouter(...) so the custom TitleStrategy replaces the router's default.
import { provideSeo } from '@elbe/ui/seo';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideSeo({
title: 'My App',
titleTemplate: '%s | My App',
origin: 'https://example.com',
description: 'Angular UI components built with Tailwind CSS.',
ogImage: '/assets/og/og.webp',
}),
],
};title, titleTemplate and origin are required; everything else is optional. These values act as defaults and can be overridden per route. Pass a function instead of a string for titleTemplate when you need full control over the rendered title.
Route metadata
Attach SEO values to a route with the typesafe meta helper. Titles come from the route's title; everything else lives in data.meta.
import { meta } from '@elbe/ui/seo/config';
export const routes: Routes = [
{
path: 'components',
title: 'Components',
data: {
...meta({
description: 'All available elbe/ui components.',
ogImage: '/assets/og/components.webp',
robots: 'index, follow',
}),
},
},
]; On navigation the strategy walks the activated route chain and merges data.meta from parent to child, so a child overrides its parent. The merged config is applied together with the defaults from provideSeo.
Excluding a page
Add robots: 'noindex, follow' to a route's meta to keep it out of search indexes. This is useful for previews, legal pages and 404s.
Imperative API
Inject ElbSeo to update tags outside of navigation, for example after asynchronously loading content. set() accepts any subset of the config.
import { ElbSeo } from '@elbe/ui/seo';
private readonly seo = inject(ElbSeo);
this.seo.setDescription('Loaded description');
this.seo.setRobots('noindex, follow');
this.seo.setCanonical('/components/gallery');Canonical URLs
The canonical URL is resolved against the configured origin: relative route paths are normalized and fragments are stripped, so /components/gallery#preview becomes https://example.com/components/gallery.