The layout of a documentation site is three components from @ng-doc/app: holds the page, is the header bar, and lists your pages. This page shows what you can put in them, how to size them, and how to replace the navbar or the sidebar with your own component.
See it
The root component of this site uses the whole layout:
<ng-doc-root >
<ng-doc-navbar >
<a ngDocNavbarLeft routerLink="/">My library</a>
<nav ngDocNavbarCenter aria-label="Primary">
<a routerLink="/docs/get-started/installation">Guides</a>
<a routerLink="/docs/api">API</a>
</nav>
<ng-doc-theme-toggle ngDocNavbarRight />
</ng-doc-navbar >
<ng-doc-sidebar />
<router-outlet />
</ng-doc-root > places the navbar at the top, the sidebar on the left and everything else, usually the router-outlet, in the page area. Its first focusable element is a "Skip to content" link, shown only while it has focus, that moves keyboard focus past the navbar and the sidebar.
Root
| Input | Type | Default | Description |
|---|---|---|---|
sidebar | boolean | true | Shows the sidebar. Turn it off on pages without navigation, such as a landing page. |
noWidthLimit | boolean | false | Lets the page use the full width of the window instead of --ng-doc-app-max-width. |
footerContent | | '' | Content below the page: a string, a template or a component. Without it, the layout renders no footer. |
A footer from a template:
<ng-doc-root [footerContent]="footer">
<!-- The navbar, the sidebar and the router outlet -->
</ng-doc-root >
<ng-template #footer>MIT License</ng-template>The navbar lays out, from left to right:
- A menu button that opens the sidebar. It shows only at 900px and below, where the sidebar is an overlay.
- The content marked with
ngDocNavbarLeft, such as the logo. - The content marked with
ngDocNavbarCenter, such as links to the sections of the site. It is hidden at 1024px and below. - The search field (
Search and command palette ). - The content marked with
ngDocNavbarRight, such as the theme toggle or a link to your repository.
The markers are plain attributes, so you don't need to import anything for them. Put any element in the navbar:
<ng-doc-navbar >
<a ngDocNavbarLeft routerLink="/">
<img src="images/logo.svg" alt="" width="28" height="28" />
My library
</a>
<ng-doc-theme-toggle ngDocNavbarRight />
<a ngDocNavbarRight ng-doc-button-icon size="large" href="https://github.com/me/my-library" target="_blank" rel="noopener" aria-label="My library on GitHub" ngDocTooltip ="Repository on GitHub">
<ng-doc-icon customIcon="github" size="24" />
</a>
</ng-doc-navbar > switches between the Auto, Light and Dark themes in turn ( from @ng-doc/app, and , and from @ng-doc/ui-kit. The github icon is a custom icon (
| Input | Type | Default | Description |
|---|---|---|---|
search | boolean | true | Shows the search field. |
hamburger | boolean | true | Shows the menu button at 900px and below. Turn it off on pages without a sidebar. |
glassEffect | boolean | true | Makes the bar translucent and blurs the page behind it. Without it, the bar uses --ng-doc-navbar-background. |
Escape closes the sidebar overlay and returns focus to the menu button.
lists your categories and pages, in the order and with the options that you set in ng-doc.category.ts and ng-doc.page.ts (
Sizes and colors
Override these CSS variables in your global styles, for example in styles.css:
:root {
--ng-doc-app-max-width: 1600px;
--ng-doc-sidebar-width: 320px;
}| Variable | Default | Description |
|---|---|---|
--ng-doc-app-max-width | 1440px | The widest the navbar content and the page area get. |
--ng-doc-app-horizontal-padding | 24px | Padding at the sides of the navbar, the sidebar and the page. |
--ng-doc-navbar-height | 60px | The height of the navbar. The page starts below it. |
--ng-doc-navbar-background | --ng-doc-base-0 | The navbar color. With glassEffect, it is mixed with the page. |
--ng-doc-navbar-border | 1px solid var(--ng-doc-border-color) | The line below the navbar. |
--ng-doc-navbar-horizontal-padding | --ng-doc-app-horizontal-padding | Padding at the sides of the navbar. |
--ng-doc-sidebar-width | 288px | The width of the sidebar. |
--ng-doc-sidebar-background | --ng-doc-base-0 | The sidebar color. |
--ng-doc-sidebar-horizontal-padding | --ng-doc-app-horizontal-padding | Padding at the sides of the sidebar. |
--ng-doc-content-max-width | 760px | The widest the text of a guide page gets. |
--ng-doc-api-content-max-width | 880px | The widest an API page gets. |
--ng-doc-toc-width | 240px | The width of the "On this page" rail on the right of a page. |
Colors are described in
To replace the navbar, put your own component in instead of , and mark it with the attribute:
<ng-doc-root >
<app-navbar ngDocCustomNavbar />
<ng-doc-sidebar />
<router-outlet />
</ng-doc-root > gives it the navbar's place. At 900px and below, your navbar needs a button that opens the sidebar. Toggle it with , and add the search with :
import { ChangeDetectionStrategy , Component , inject } from '@angular/core';
import { RouterLink } from '@angular/router';
import { NgDocSearchComponent , NgDocSidebarService } from '@ng-doc/app';
@Component ({
selector: 'app-navbar',
imports: [RouterLink , NgDocSearchComponent ],
template: `
<button type="button" aria-controls="ng-doc-sidenav" [attr.aria-expanded]="sidebar.expandedState()" (click)="sidebar.toggle()">Menu </button>
<a routerLink="/">My library</a>
<ng-doc-search />
`,
styles: `
:host {
display: flex;
align-items: center;
gap: 16px;
height: var(--ng-doc-navbar-height);
padding: 0 var(--ng-doc-app-horizontal-padding);
background: var(--ng-doc-navbar-background);
border-bottom: var(--ng-doc-navbar-border);
}
`,
changeDetection: ChangeDetectionStrategy .OnPush,
})
export class NavbarComponent {
protected readonly sidebar = inject (NgDocSidebarService );
}expandedState() tells whether the sidebar is open, and isMobile whether the window is narrow enough for the sidebar to be an overlay. show() and hide() open and close it.
To replace the sidebar, mark your own component with the attribute:
<ng-doc-root >
<ng-doc-navbar />
<app-sidebar ngDocCustomSidebar />
<router-outlet />
</ng-doc-root >The categories and pages come from the token. Its navigation is a tree of items: a category has children, and every item has a title and a route.
import { ChangeDetectionStrategy , Component , inject } from '@angular/core';
import { RouterLink , RouterLinkActive } from '@angular/router';
import { NG_DOC_CONTEXT } from '@ng-doc/app';
@Component ({
selector: 'app-sidebar',
imports: [RouterLink , RouterLinkActive ],
template: `
<nav aria-label="Documentation">
@for (item of navigation; track item.route) {
@if (item.children?.length) {
<h2>{{ item.title }}</h2>
@for (child of item.children; track child.route) {
<a [routerLink]="child.route" routerLinkActive="active">{{ child.title }}</a>
}
} @else {
<a [routerLink]="item.route" routerLinkActive="active">{{ item.title }}</a>
}
}
</nav>
`,
changeDetection: ChangeDetectionStrategy .OnPush,
})
export class SidebarComponent {
protected readonly navigation = inject (NG_DOC_CONTEXT ).navigation;
}Categories can be nested more deeply than this example shows. Items with set are not meant to be listed.
Serve the docs under a route
By default, the documentation routes start at the root of the application, such as /getting-started. To keep other pages at the root, for example a landing page, serve the documentation under its own route, such as /docs.
First, take the NgDoc layout out of the root component. ng add puts it in the root component's template, so it wraps every route: your other pages would render inside the documentation layout, and the documentation would get a second layout under /docs. Replace the template with your application's own shell, which keeps a <router-outlet />:
<!-- Your header, footer and other parts of the shell -->
<router-outlet />Remove , and from the root component's imports, and keep . The documentation layout moves to a component of its own.
Create a component for the documentation layout, and export its routes:
import { ChangeDetectionStrategy , Component } from '@angular/core';
import { RouterOutlet , Routes } from '@angular/router';
import { NgDocNavbarComponent , NgDocRootComponent , NgDocSidebarComponent } from '@ng-doc/app';
import { NG_DOC_ROUTING } from '@ng-doc/generated';
@Component ({
selector: 'app-docs',
imports: [RouterOutlet , NgDocRootComponent , NgDocNavbarComponent , NgDocSidebarComponent ],
template: `
<ng-doc-root>
<ng-doc-navbar>
<span ngDocNavbarLeft>My library</span>
</ng-doc-navbar>
<ng-doc-sidebar />
<router-outlet />
</ng-doc-root>
`,
changeDetection: ChangeDetectionStrategy .OnPush,
})
export class DocsComponent {}
const routes: Routes = [{ path: '', component: DocsComponent, children: NG_DOC_ROUTING }];
export default routes;Load these routes lazily under the docs path of the application router:
provideRouter ([...routes, { path: 'docs', loadChildren: () => import('./docs/docs.routes') }], withInMemoryScrolling ({ scrollPositionRestoration: 'enabled', anchorScrolling: 'enabled' }));routes holds your own pages, such as the landing page at ''. Remove the ...NG_DOC_ROUTING that ng add added to this list: the documentation routes now come from docs.routes.ts.
NgDoc generates the links between pages, so it needs to know the route too. Set routePrefix in the configuration file (
import { NgDocConfiguration } from '@ng-doc/builder';
const config : NgDocConfiguration = {
routePrefix: 'docs',
};
export default config ;Keep your app header above the docs
To show your application's header on the documentation pages too, put it in the documentation layout as the custom navbar (see
import { ChangeDetectionStrategy , Component , inject , input } from '@angular/core';
import { RouterLink } from '@angular/router';
import { NgDocSearchComponent , NgDocSidebarService } from '@ng-doc/app';
@Component ({
selector: 'app-header',
imports: [RouterLink , NgDocSearchComponent ],
template: `
@if (inDocs()) {
<button type="button" aria-controls="ng-doc-sidenav" [attr.aria-expanded]="sidebar.expandedState()" (click)="sidebar.toggle()">Menu </button>
}
<a routerLink="/">My app</a>
<a routerLink="/docs/getting-started">Docs</a>
@if (inDocs()) {
<ng-doc-search />
}
`,
styles: `
:host {
display: flex;
align-items: center;
gap: 16px;
height: var(--ng-doc-navbar-height);
padding: 0 var(--ng-doc-app-horizontal-padding);
background: var(--ng-doc-navbar-background);
border-bottom: var(--ng-doc-navbar-border);
}
`,
changeDetection: ChangeDetectionStrategy .OnPush,
})
export class AppHeader {
readonly inDocs = input (false);
protected readonly sidebar = inject (NgDocSidebarService );
}In the documentation layout, the header takes the place of :
<ng-doc-root >
<app-header ngDocCustomNavbar [inDocs]="true" />
<ng-doc-sidebar />
<router-outlet />
</ng-doc-root >In the imports of DocsComponent, replace with AppHeader. The shell hides its own copy of the header under /docs:
import { ChangeDetectionStrategy , Component , inject } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { NavigationEnd , Router , RouterOutlet } from '@angular/router';
import { filter , map } from 'rxjs';
import { AppHeader } from './header/header';
@Component ({
selector: 'app-root',
imports: [RouterOutlet , AppHeader],
template: `
@if (!inDocs()) {
<app-header />
}
<router-outlet />
`,
changeDetection: ChangeDetectionStrategy .OnPush,
})
export class App {
private readonly router = inject (Router );
protected readonly inDocs = toSignal (
this.router.events.pipe (
filter ((event) => event instanceof NavigationEnd ),
map (() => this.router.url.startsWith('/docs')),
),
{ initialValue: false },
);
} Gotchas
WarningThe
component places only its direct children marked as the navbar or the sidebar. A navbar or sidebar wrapped in another element, such as ang-doc-root div, lands in the page area.
WarningNgDoc's header is fixed at the top of the window, even when the layout has no navbar. A header of your application placed above
ends up under it and can't be clicked. Put it in the layout as the custom navbar instead (ng-doc-root Keep your app header above the docs ).
Next: