This documentation is also published as Markdown for efficient machine reading: the whole site is indexed at /llms.txt, and every page has a clean Markdown copy under /_llms/. These are generated from the same source and cost far fewer tokens to read than this rendered HTML.

Skip to main content Skip to navigation
Guides

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

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.

csharp
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.

csharp
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).

csharp
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();

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 run and open /. The hero title and description appear at the top, and the "My Work" card lists each Project entry with a working link.
  • The social-icon row under the card renders one icon per SocialLink, each linking to its Url. The top-nav and footer list every HeaderLink.
  • Run dotnet run -- build. The generated index.html contains every hero/project/socials/nav string, and the build report shows no 500s.