---
title: Populate the blog homepage
description: "Populate the BlogSite homepage — hero block, My Work card, social-icon row, and top-nav links — from the four init-only properties on BlogSiteOptions."
canonical_url: https://usepennington.net/how-to/theming/blogsite-homepage/
sidecar_url: https://usepennington.net/how-to/theming/blogsite-homepage.md
content_hash: sha256:3ba9735bad25cddee27d9205ffb4e2f24c0c06e3ca992941c97ac2426e8cd13d
tokens: 2147
uid: how-to.theming.blogsite-homepage
reading_time_minutes: 3
---

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](https://usepennington.net/reference/api/blog-site-options.md) reference; this page shows how to fill them. For the hand-held walkthrough, see [Add a hero, projects, and social links](https://usepennington.net/tutorials/blogsite/hero-projects-socials.md).

 
## Before you begin

 
 - A running BlogSite built with `AddBlogSite` / `UseBlogSite` (see [Scaffold a blog with BlogSite](https://usepennington.net/tutorials/blogsite/scaffold.md) if not).
 - At least one post under `BlogContentPath` so the recent-posts slot is not empty (see [Author your first post with BlogSiteFrontMatter](https://usepennington.net/tutorials/blogsite/first-post.md)).
 - 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](https://github.com/usepennington/pennington/tree/main/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:symbol,bodyonly
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:symbol,bodyonly
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:symbol,bodyonly
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 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.
 
 
## Related

 
 - Tutorial: [Add a hero, projects, and social links](https://usepennington.net/tutorials/blogsite/hero-projects-socials.md) — the hand-held walkthrough of the same four sections.
 - Reference: [BlogSiteOptions](https://usepennington.net/reference/api/blog-site-options.md) — the full property catalog (site metadata, content paths, feeds, fonts).
 - Background: [What the DocSite and BlogSite templates wire for you](https://usepennington.net/explanation/positioning/docsite-positioning.md) — what each template assembles and where the wiring stops.
 
 
[Previous
                
                Switch the body and heading typeface](https://usepennington.net/how-to/theming/fonts.md)[Next
                    
                Version a DocSite](https://usepennington.net/how-to/versioning/docsite.md)