A fluent HTML builder and server-side rendering library for ASP.NET Core Minimal APIs. Build HTML with C# using RenderFragment templates, the Html fluent API, TableBuilder, SelectBuilder, and ComponentHelper.
using RazorHelpers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorHelpers(); // Required before Build()
var app = builder.Build();
// Return HTML from a Minimal API endpoint
app.MapGet("/", () =>
{
var fragment = Html.Div()
.Class("container")
.Child(Html.H1("Hello World"))
.Child(Html.P("Welcome to RazorHelpers"))
.Render();
return RazorResults.Razor(fragment);
});
app.Run();
// Return IResult from a RenderFragment
RazorResults.Razor(fragment)
RazorResults.Razor(fragment, model)
// Render to HTML string
await fragment.RenderAsync(services)
await fragment.RenderAsync(model, services)
// Render component class to string
await ComponentHelper.RenderComponentAsync<T>(services)
// Build HTML fluently
Html.Div().Class("x").Child(Html.P("text")).Render()
// Build tables from collections
Html.Table(items).Column("Name", x => x.Name).Render()
// Build selects from collections
Html.Select(items, "name").Value(x => x.Id).Render()
The Html static class provides factory methods for all standard HTML elements.
Div, Span, P, Section, Article, Header, Footer, Main, Nav, Aside
H1, H2, H3, H4, H5, H6
Strong, Em, B, I, U, Code, Pre, Kbd, Mark, Blockquote, and more
Form, Input, Textarea, Button, Label, Select, Fieldset, Progress, Meter
A, Img, Video, Audio, Iframe, Figure, Picture
Ul, Ol, Li, Dl, Dt, Dd -- plus collection-based Ul<T>
Html.Div()
.Id("main")
.Class("container", "mt-4") // Multiple classes
.ClassIf("active", isActive) // Conditional class
.Attr("role", "main") // Any attribute
.Data("id", "123") // data-* attribute
.Style("color", "red") // Inline style
.Child(Html.H1("Title")) // Add child element
.Children(Html.P("A"), Html.P("B")) // Multiple children
.Render()
var items = new[] { "Apple", "Banana", "Cherry" };
Html.Ul(items, x => x)
// <ul><li>Apple</li><li>Banana</li><li>Cherry</li></ul>
// Or with Html.Each for custom elements
Html.Each(products, p =>
Html.Div().Class("card")
.Child(Html.H3(p.Name))
.Child(Html.Span($"${p.Price:F2}")))
Build HTML tables from collections with column definitions, row styling, and rich content.
// Column definitions (recommended)
Html.Table(users)
.Class("table", "table-hover")
.Column("Name", u => u.Name)
.Column("Email", u => Html.A($"mailto:{u.Email}", u.Email))
.Column("Status", u => Html.Span(u.IsActive ? "Active" : "Inactive")
.Class(u.IsActive ? "text-success" : "text-danger"))
.RowClass(u => u.IsActive ? "" : "table-secondary")
.Render()
Html.Table()
.Class("table", "table-striped")
.Caption("User List")
.Header("Name", "Email", "Role")
.Row("John Doe", "john@example.com", "Admin")
.Row("Jane Smith", "jane@example.com", "User")
.Render()
Build HTML select elements from collections with grouping, selected state, and placeholder support.
// From collection
Html.Select(countries, "country")
.Class("form-select")
.Placeholder("Select a country...")
.Value(c => c.Code)
.Text(c => c.Name)
.SelectedValue("uk")
.Render()
// With automatic grouping
Html.Select(cars, "car")
.Value(c => c.Code)
.Text(c => c.Name)
.GroupBy(c => c.Country) // Creates <optgroup>
.Render()
Html.Select("car")
.OptGroup("Swedish Cars")
.Option("volvo", "Volvo")
.Option("saab", "Saab")
.EndGroup()
.OptGroup("German Cars")
.Option("mercedes", "Mercedes")
.Option("bmw", "BMW")
.EndGroup()
.Render()
For more complex UI, use RenderFragment delegates with the RenderTreeBuilder API.
public record User(string Name, string Email, int Age);
RenderFragment<User> userCard = user => builder =>
{
var seq = 0;
builder.OpenElement(seq++, "div");
builder.AddAttribute(seq++, "class", "user-card");
builder.OpenElement(seq++, "h2");
builder.AddContent(seq++, user.Name); // Auto HTML-encoded
builder.CloseElement();
builder.OpenElement(seq++, "p");
builder.AddContent(seq++, $"Email: {user.Email}");
builder.CloseElement();
builder.CloseElement();
};
app.MapGet("/user/{name}", (string name) =>
{
var user = new User(name, $"{name}@example.com", 30);
return RazorResults.Razor(userCard, user);
});
Render Razor component classes to HTML strings for use in Minimal API endpoints.
// Without parameters
var html = await ComponentHelper.RenderComponentAsync<GreetingComponent>(services);
// With parameters dictionary
var parameters = new Dictionary<string, object?>
{
["Name"] = name,
["ShowTime"] = true
};
var html = await ComponentHelper.RenderComponentAsync<GreetingComponent>(services, parameters);
// With single parameter (convenience)
var html = await ComponentHelper.RenderComponentAsync<GreetingComponent, string>(
services, "Name", name);
Html.Div(userInput), .Text(userInput), AddContent() -- all auto-encode HTML to prevent XSS.
.Raw(content), AddMarkupContent() -- never use with user input. Only for trusted/sanitized content.
Define static readonly RenderFragment<T> fields to avoid creating new delegates per request.
Column definitions are more efficient and auto-generate headers from complex tables.
Create new builder instances per-request. Do not share across threads.