Add doc pages and link between them
Build out a Guides area with two content pages, wire sibling navigation, hub-style absolute links, and rename-safe uid cross-references.
By the end of this tutorial the Guides area has two new pages — install.md and configure.md — wired into the sidebar in order: sequence, cross-linked with relative paths, and reachable from a hub index.md that uses both absolute paths and a uid:-based xref: link.
Prerequisites
- .NET 10 SDK installed
- Completed Scaffold a DocSite (or have a DocSite project with a
Content/guides/folder ready — this tutorial adds pages to it)
The finished code for this tutorial lives in examples/DocSitePagesAndLinksExample.
1. Add two content pages
Let's drop two markdown files into the Guides area and watch them slot into the sidebar. The pages stand alone for now — linking arrives in the next unit.
Create Content/guides/install.md
Add a new file at Content/guides/install.md with the markdown below. The four front-matter keys are the ones DocSiteFrontMatter reads for sidebar wiring: title is the link label, description becomes the meta tag, sectionLabel carries through to breadcrumbs and prev/next chrome, and order decides where the page sorts among siblings.
---
title: Install Pennington
description: Add the Pennington DocSite package and wire AddDocSite + UseDocSite into a fresh ASP.NET host.
sectionLabel: Guides
order: 20
---
# Install Pennington
Install Pennington into an ASP.NET project with one NuGet package and three lines of DI wiring.
## 1. Add the package
```bash
dotnet add package Pennington.DocSite
```
## 2. Wire DocSite in `Program.cs`
Three calls — register the services, mount the middleware, hand control to the host:
```csharp
builder.Services.AddDocSite(() => new DocSiteOptions { /* ... */ });
app.UseDocSite();
await app.RunDocSiteAsync(args);
```
The host is now ready for content. Drop markdown files under `Content/guides/` and they appear in the sidebar on the next request.
Create Content/guides/configure.md
Add a second file next to the first with the markdown below. Note order: 30 — a larger number than install's order: 20, so configure sorts after install in the sidebar.
---
title: Configure the site
description: Pick a site title, set the GitHub link, and decide on a single area or multiple.
sectionLabel: Guides
order: 30
---
# Configure the site
`DocSiteOptions` is the one options record `AddDocSite` reads. Set the fields that surface in the rendered chrome and the rest of the template falls into place.
## Fields worth setting first
- `SiteTitle` — appears in the header and the `<title>` tag.
- `Description` — meta description used in search snippets and social cards.
- `GitHubUrl` — surfaces the GitHub icon in the header.
- `HeaderContent` / `FooterContent` — raw HTML slots, useful for a logo and a copyright line.
## Areas — one or many?
`Areas` is an `IReadOnlyList<ContentArea>`. One entry is enough to ship; more entries turn on the area selector and split the sidebar by top-level folder. Stick with a single area until the content outgrows it.
For deeper coverage of section grouping and order: strategy, see Organize content with sections and areas.
Checkpoint
- Run
dotnet runand visithttp://localhost:5000/guides/install— the Install Pennington page renders. - Visit
http://localhost:5000/guides/configure— the Configure the site page renders. - The Guides sidebar lists both new pages, with Install Pennington above Configure the site (sorted by
order:).
2. Link siblings with relative paths
Both pages exist but neither knows about the other. Adding a relative-path link at the bottom of each one creates a natural "previous / next" flow without hardcoding the area slug.
Add a "Next" footer to install.md
Append a ## Next heading and a relative-path link to the bottom of install.md. ./configure resolves against the current page's URL (/guides/install), so it points at /guides/configure no matter where the area sits.
---
title: Install Pennington
description: Add the Pennington DocSite package and wire AddDocSite + UseDocSite into a fresh ASP.NET host.
sectionLabel: Guides
order: 20
---
# Install Pennington
Install Pennington into an ASP.NET project with one NuGet package and three lines of DI wiring.
## 1. Add the package
```bash
dotnet add package Pennington.DocSite
```
## 2. Wire DocSite in `Program.cs`
Three calls — register the services, mount the middleware, hand control to the host:
```csharp
builder.Services.AddDocSite(() => new DocSiteOptions { /* ... */ });
app.UseDocSite();
await app.RunDocSiteAsync(args);
```
The host is now ready for content. Drop markdown files under `Content/guides/` and they appear in the sidebar on the next request.
## Next
Pick a site title and decide on areas in [Configure the site](./configure).
Add a "Previously" footer to configure.md
Mirror the same shape on configure.md with a ./install link back to the first page. Both pages now link to their sibling with a path that survives any move of the Content/guides/ folder.
---
title: Configure the site
description: Pick a site title, set the GitHub link, and decide on a single area or multiple.
sectionLabel: Guides
order: 30
---
`DocSiteOptions` is the one options record `AddDocSite` reads. Set the fields that surface in the rendered chrome and the rest of the template falls into place.
## Fields worth setting first
- `SiteTitle` — appears in the header and the `<title>` tag.
- `Description` — meta description used in search snippets and social cards.
- `GitHubUrl` — surfaces the GitHub icon in the header.
- `HeaderContent` / `FooterContent` — raw HTML slots, useful for a logo and a copyright line.
## Areas — one or many?
`Areas` is an `IReadOnlyList<ContentArea>`. One entry is enough to ship; more entries turn on the area selector and split the sidebar by top-level folder. Stick with a single area until the content outgrows it.
## Previously
[Install Pennington](./install) covered getting the package and wiring in place.
Checkpoint
- Reload
http://localhost:5000/guides/install— a Configure the site link sits at the bottom of the page. Click it. - The browser lands on
/guides/configure. A Install Pennington link at the bottom of that page returns to the first. - View source on either page: the relative
./configureand./installmarkdown links rendered ashref="/guides/configure"andhref="/guides/install".
3. Turn the index into a hub with absolute paths
The Content/guides/index.md page from the scaffold still says "Walkthroughs and how-tos live in this folder" — a placeholder that no longer matches the content under it. Let's rewrite it as a hub that links to both pages with absolute paths.
Replace index.md with the hub markdown below
Absolute paths (/guides/install) survive folder moves of the source page. For the full link-form rundown, see Link between pages without hardcoding URLs.
---
title: Guides
description: Onboarding walkthroughs for a fresh Pennington DocSite.
sectionLabel: Guides
order: 10
---
# Guides
Two short walkthroughs cover the path from empty project to running site.
- [Install Pennington](/guides/install) — add the package and wire `AddDocSite`.
- [Configure the site](/guides/configure) — set the site title, GitHub link, and areas.
Checkpoint
- Visit
http://localhost:5000/guides/— the Guides landing page now lists the two walkthroughs. - Click Install Pennington — the browser navigates to
/guides/install. - Click Configure the site — the browser navigates to
/guides/configure.
4. Make one link rename-safe with uid: + xref:
Absolute paths break the moment the target file moves or gets renamed. A uid: declared in the page's front matter gives the page a stable identifier; xref: links resolve through it, so the link survives the file moving or even the URL changing.
Add uid: guides.install to install.md's front matter
Open install.md and add one front-matter key — the page is now reachable by xref:guides.install no matter where the file lives.
---
title: Install Pennington
description: Add the Pennington DocSite package and wire AddDocSite + UseDocSite into a fresh ASP.NET host.
uid: guides.install
sectionLabel: Guides
order: 20
---
Install Pennington into an ASP.NET project with one NuGet package and three lines of DI wiring.
## 1. Add the package
```bash
dotnet add package Pennington.DocSite
```
## 2. Wire DocSite in `Program.cs`
Three calls — register the services, mount the middleware, hand control to the host:
```csharp
builder.Services.AddDocSite(() => new DocSiteOptions { /* ... */ });
app.UseDocSite();
await app.RunDocSiteAsync(args);
```
The host is now ready for content. Drop markdown files under `Content/guides/` and they appear in the sidebar on the next request.
## Next
Pick a site title and decide on areas in [Configure the site](./configure).
Swap the install link in index.md to use xref:
Open index.md and replace /guides/install with xref:guides.install. The configure link stays as an absolute path — handy for seeing both forms side by side in the rendered output.
---
title: Guides
description: Onboarding walkthroughs for a fresh Pennington DocSite.
sectionLabel: Guides
order: 10
---
Two short walkthroughs cover the path from empty project to running site.
- [Install Pennington](xref:guides.install) — add the package and wire `AddDocSite`.
- [Configure the site](/guides/configure) — set the site title, GitHub link, and areas.
Checkpoint
- Reload
http://localhost:5000/guides/— both links in the hub still work. The rendered<a>for Install Pennington points at/guides/installjust as the absolute-path version did. - View source: the
xref:guides.installhref has been rewritten to the canonical URL. The xref form is the same shape an editor would have produced — but the source markdown now survives any rename ofinstall.md.
Summary
- Two markdown files under
Content/guides/showed up in the sidebar without any extra wiring, sorted byorder:from front matter. - Relative paths (
./configure) link tightly coupled sibling pages — the form that survives area-folder renames. - Absolute paths (
/guides/configure) link from a hub where the source page may move but the target's location is stable. uid:plusxref:— the rename-safe form — turns the page identifier itself into the link target.- For the full link-form reference (anchors, assets, sub-path deployments), see Link between pages without hardcoding URLs. For deeper
uid:semantics, see Cross-reference resolution.