
One of the last blog posts (Text and EMail Templates with Handlebars.NET ) was generally about HandleBars.NET - a very popular template engine. This post is about how you can easily implement layouts with Handlebars.
The snippet in the previous post was as follows:
1// MyTemplateProvider.cs
2
3 public MyTemplateProvider()
4 {
5 _handlebars = Handlebars.Create();
6
7 Init(); // Add this
8 }
9
10 private void Init()
11 {
12 // Add Header Template
13 _handlebars.RegisterTemplate("Header_Template", @"<strong>MyCompany - {{Title}}</strong>");
14
15 // Add Footer Template
16 _handlebars.RegisterTemplate("Footer_Template", @"<i>MyCompany - Copyright 2023</i>");
17
18 // Register Welcome Mail
19 _handlebars.RegisterTemplate("WelcomeMail_Template",
20 """
21 <div>
22 <h1>{{>Header_Template}}</h1>
23 <div class="body">
24 <h3>Welcome to our demo {{UserName}}!</h3>
25 <p>Thank you for registering. Have fun!</p>
26 </div>
27 <footer>{{>Footer_Template}}</footer>
28 </div>
29 """);
30 }
As you can see, a template is registered that references other templates - but explicitly. I therefore have to take care of the frame - in this case the header and footer - for my actual content myself. This is not nice and represents a redundancy.
Partial Blocks
Handlebars supports a functionality called Partial Blocks. While simple Partials represent a content block, partial blocks are the construct around it. In Razor, this is comparable to sections. Partial blocks can therefore be used to represent the surrounding content - like our layouts.
1_handlebars.RegisterTemplate("MailLayout", """
2 <div>
3 <h1><strong>MyCompany - {{Title}}</strong></h1>
4 <div class="body">
5 {{> content}}
6 </div>
7 <footer><i>MyCompany - Copyright {{On.Year}}</i></footer>
8 </div>
9 """);
Partial blocks are also registered as templates, but have the special feature that they contain the reserved partial keyword content. This is then replaced by the actual content you have in your template.
The layout can then be referenced in the actual template by specifying the partial block:
1_handlebars.RegisterTemplate("WelcomeMail_Template",
2 """{{#> MailLayout}}
3 <h3>Welcome to our demo {{UserName}}!</h3>
4 <p>Thank you for registering. Have fun!</p>
5 {{/MailLayout}}
6 """);
Full Sample
1using HandlebarsDotNet;
2
3namespace BenjaminAbt.Samples.HandlebarsNET;
4
5internal class Program
6{
7 static void Main(string[] args)
8 {
9 MyTemplateProvider templateProvider = new();
10
11 List<string> userNames = ["Batman", "Robin"];
12 foreach (var userName in userNames)
13 {
14 string text = templateProvider.RenderWelcomeMail(userName);
15
16 Console.WriteLine($"To: {userName}");
17 Console.WriteLine(text);
18 Console.WriteLine("-------------------");
19 }
20 }
21}
22
23// MyTemplateProvider.cs
24public class MyTemplateProvider
25{
26 private readonly IHandlebars _handlebars;
27
28 public MyTemplateProvider()
29 {
30 _handlebars = Handlebars.Create();
31
32 Init(); // Add this
33 }
34
35 private void Init()
36 {
37
38 _handlebars.RegisterTemplate("MailLayout", """
39 <div>
40 <h1><strong>MyCompany - {{Title}}</strong></h1>
41 <div class="body">
42 {{> content}}
43 </div>
44 <footer><i>MyCompany - Copyright {{On.Year}}</i></footer>
45 </div>
46 """);
47
48 // Register Welcome Mail
49 _handlebars.RegisterTemplate("WelcomeMail_Template", InternalRegisterTemplateWithLayout(
50 """
51 <h3>Welcome to our demo {{UserName}}!</h3>
52 <p>Thank you for registering. Have fun!</p>
53 """));
54 }
55
56 private string InternalRegisterTemplateWithLayout(string template)
57 => "{{#> MailLayout}}" + template + "{{/MailLayout}}";
58
59 private HandlebarsTemplate<object, object>? _welcomeTemplate = null;
60 public string RenderWelcomeMail(string userName)
61 {
62 _welcomeTemplate ??= _handlebars.Compile("{{> WelcomeMail_Template}}");
63
64 var data = new
65 {
66 Title = "Welcome!",
67 UserName = userName,
68 On = DateTimeOffset.UtcNow
69 };
70
71 var text = _welcomeTemplate(data);
72 return text;
73 }
74}
Have fun!
Related articles

Feb 20, 2026 · 9 min read
.NET 11 Preview 1 Is Here: What's New and What to Expect
The .NET team just released the first preview of .NET 11 and there is already a lot to talk about. While this is an early preview - not a …

Jan 02, 2026 · 4 min read
Build a Custom FeatureGate Attribute in ASP.NET Core with C#
Feature management is a key technique in modern web applications, allowing you to enable or disable features dynamically without redeploying …

Nov 28, 2025 · 5 min read
Custom IFeatureDefinitionProvider: Feature Flags from Tests and Databases
Feature flags are a great way to ship safely, run experiments and keep production changes reversible. In .NET, the de-facto standard is …
Let's Work Together
Looking for an experienced Platform Architect or Engineer for your next project? Whether it's cloud migration, platform modernization or building new solutions from scratch - I'm here to help you succeed.

Comments