Populate the blog homepage
Populate the BlogSite homepage — hero block, My Work card, social-icon row, and top-nav links — from the four init-only properties on BlogSiteOptions.
When a BlogSite homepage needs its hero block, "My Work" card, social-icon row, and top-nav links populated in one pass, four init-only properties on BlogSiteOptions cover it — HeroContent, MyWork, Socials, and MainSiteLinks. Their record types (HeroContent, Project, SocialLink, HeaderLink) are catalogued in the BlogSiteOptions reference; this page shows how to fill them. For the hand-held walkthrough, see Add a hero, projects, and social links.
Before you begin
- A running BlogSite built with
AddBlogSite/UseBlogSite(see Scaffold a blog with BlogSite if not). - At least one post under
BlogContentPathso the recent-posts slot is not empty (see Author your first post with BlogSiteFrontMatter). - A single
AddBlogSite(() => new BlogSiteOptions { ... })call to edit — the four sections are init-only properties on that same record literal.
For a working setup, see examples/BlogSiteHeroProjectsSocialsExample.
Options
Set HeroContent for the headline block
HeroContent is a two-field positional record (Title, Description) rendered at the top of /. Description is emitted as a MarkupString in Home.razor, so light HTML is permitted; plain prose works for most sites.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBlogSite(() => new BlogSiteOptions
{
SiteTitle = "Hero Blog",
SiteDescription = "A BlogSite tutorial app demonstrating hero, projects, and social links.",
CanonicalBaseUrl = "https://example.com",
AuthorName = "Author Name",
AuthorBio = "Writing about software, tools, and the occasional side project.",
HeroContent = new HeroContent(
Title: "Field notes from a weekend content engine",
Description: "I build small tools for small problems. This is where I write about them."),
});
var app = builder.Build();
app.UseBlogSite();
app.RunBlogSiteAsync(args).GetAwaiter().GetResult();
Fill MyWork with Project entries
MyWork takes a Project[], where each Project(Title, Description, Url) renders as a linked entry in the "My Work" sidebar card. The array is rendered verbatim, so ordering entries in the initializer controls their display order.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBlogSite(() => new BlogSiteOptions
{
SiteTitle = "Hero Blog",
SiteDescription = "A BlogSite tutorial app demonstrating hero, projects, and social links.",
CanonicalBaseUrl = "https://example.com",
AuthorName = "Author Name",
AuthorBio = "Writing about software, tools, and the occasional side project.",
HeroContent = new HeroContent(
Title: "Field notes from a weekend content engine",
Description: "I build small tools for small problems. This is where I write about them."),
MyWork =
[
new Project(
Title: "Pennington",
Description: "A tiny .NET content engine for docs and blogs.",
Url: "https://github.com/example/pennington"),
new Project(
Title: "MonorailCSS",
Description: "Utility-first CSS generation for Razor.",
Url: "https://github.com/example/monorailcss"),
new Project(
Title: "Mdazor",
Description: "Inline Razor components inside Markdown.",
Url: "https://github.com/example/mdazor"),
],
});
var app = builder.Build();
app.UseBlogSite();
app.RunBlogSiteAsync(args).GetAwaiter().GetResult();
Wire Socials with the built-in icon fragments
Socials takes a SocialLink[], where SocialLink(Icon, Url) pairs a RenderFragment with an <a href> target. The four built-in fragments — GithubIcon, BlueskyIcon, LinkedInIcon, MastodonIcon — are static readonly fields on Pennington.BlogSite.Components.SocialIcons and are passed directly without any wrapper type or component registration. Add a using Pennington.BlogSite.Components; directive so the field names resolve. The same block below also fills MainSiteLinks (the next section).
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBlogSite(() => new BlogSiteOptions
{
SiteTitle = "Hero Blog",
SiteDescription = "A BlogSite tutorial app demonstrating hero, projects, and social links.",
CanonicalBaseUrl = "https://example.com",
AuthorName = "Author Name",
AuthorBio = "Writing about software, tools, and the occasional side project.",
HeroContent = new HeroContent(
Title: "Field notes from a weekend content engine",
Description: "I build small tools for small problems. This is where I write about them."),
MyWork =
[
new Project(
Title: "Pennington",
Description: "A tiny .NET content engine for docs and blogs.",
Url: "https://github.com/example/pennington"),
new Project(
Title: "MonorailCSS",
Description: "Utility-first CSS generation for Razor.",
Url: "https://github.com/example/monorailcss"),
new Project(
Title: "Mdazor",
Description: "Inline Razor components inside Markdown.",
Url: "https://github.com/example/mdazor"),
],
Socials =
[
new SocialLink(SocialIcons.GithubIcon, "https://github.com/example"),
new SocialLink(SocialIcons.BlueskyIcon, "https://bsky.app/profile/example.bsky.social"),
new SocialLink(SocialIcons.LinkedInIcon, "https://www.linkedin.com/in/example"),
new SocialLink(SocialIcons.MastodonIcon, "https://hachyderm.io/@example"),
],
MainSiteLinks =
[
new HeaderLink("Home", "/"),
new HeaderLink("Archive", "/archive"),
new HeaderLink("Tags", "/tags"),
],
});
var app = builder.Build();
app.UseBlogSite();
app.RunBlogSiteAsync(args).GetAwaiter().GetResult();
Populate MainSiteLinks for the top nav
MainSiteLinks takes a HeaderLink[], where each HeaderLink(Title, Url) appears in both the site header and footer via MainLayout.razor. Use relative URLs (/, /archive, /tags) so BaseUrlHtmlRewriter can prefix them correctly on sub-path deployments. The MainSiteLinks = [...] block sits alongside Socials in the snippet above.
Result
The homepage at / renders the hero block above the post list, the "My Work" card and social-icon row in the right rail, and every HeaderLink in both the top nav and the footer. The four sections are independent; populating any one renders that section and leaves the rest at their template defaults.
Verify
- Run
dotnet runand open/. The hero title and description appear at the top, and the "My Work" card lists eachProjectentry with a working link. - The social-icon row under the card renders one icon per
SocialLink, each linking to itsUrl. The top-nav and footer list everyHeaderLink. - Run
dotnet run -- build. The generatedindex.htmlcontains every hero/project/socials/nav string, and the build report shows no 500s.
Related
- Tutorial: Add a hero, projects, and social links — the hand-held walkthrough of the same four sections.
- Reference:
BlogSiteOptions— the full property catalog (site metadata, content paths, feeds, fonts). - Background: What the DocSite and BlogSite templates wire for you — what each template assembles and where the wiring stops.