Blazor tutorial
Razor class library components wey get parameters, ChildContent
render fragments, attribute splatting, and one bUnit test for each component.
Wetin you go build
Small contact form — input wey get label, submit button,
@bind-Value binding, real keyboard and screen-reader behaviour — first bare, then styled, for about 10 minutes.
Before you start
You need git and di .NET SDK 8 or newer. Any Blazor project dey work — Blazor Web App, Server, or WebAssembly.
Step 1 — Get di code
git clone https://github.com/LilyDesignSystem/lily-design-system
cd lily-design-system/lily-design-system-blazor-headless
dotnet build
dotnet test # bUnit — 1,400+ cases across the catalog
Di components dey live inside src/LilyBlazorHeadless/Components/ —
Button.razor, TextInput.razor — one Razor file each. Reference di project (or copy di files) from your Blazor app and add @using LilyBlazorHeadless.Components to
_Imports.razor.
Step 2 — Your first component
<Button OnClick="Save">Save</Button>
E dey render <button class="button">. Di shared parameter conventions: Label (an aria-label override),
CssClass (dem append am to di base hook),
ChildContent, and
[Parameter(CaptureUnmatchedValues = true)] attribute splatting so any extra HTML attribute go pass through.
Step 3 — Compose small form
<Form OnSubmit="HandleSubmit">
<Field Label="Full name" Required="true">
<TextInput Id="name" Label="Full name" @bind-Value="name" Required="true" />
</Field>
<Button Type="submit">Save</Button>
</Form>
@code {
private string name = "";
}
Field dey take di visible Label as im own parameter instead of nested label component — pass am once, on
Field, and TextInputfor
Label dey provide di accessible name.
Verified 2026-08-29: earlier draft nest separate Label component inside Field, wey render two labels (one empty) because Field
already dey render im own from di Label parameter — dem catch am by checking di component source; Form no get im own Label parameter, so di earlier draft usage of
<Form> dem correct am to comot one instead of to invent attribute wey no exist. Di
contact-form composed route
na di same pattern, wey real e2e and axe tests don exercise.
Check your work: run di app and di form go look plain — exactly as dem plan am: di styling still dey come. Press Tab: focus go move through every control, di label go dey announced, and submit dey work. Di behaviour don finish; di look na yours and e be next.
Step 4 — Style am
Style di class hooks — .button, .text-input,
.label, .field — inside app.css, or link ready-made theme inside App.razor /
index.html:
<link rel="stylesheet" href="themes/wireframe.css" />
Step 5 — See everything dey work
Di Blazor Web example app show di full catalog styled and demoed, with Playwright e2e tests:
git clone https://github.com/LilyDesignSystem/lily-design-system
cd lily-design-system/lily-design-system-blazor-web-examples
dotnet run --project src/LilyBlazorWebExamples
Next steps
- Theming — runtime switching with di Blazor theme-picker helper (Razor class library for NuGet).
- Preference helpers — language and text size.
- Component catalog — props, ARIA, and keyboard for each component.
You get questions as you dey go? Di help page full of answers — and if any step fit clearer, tell us and we go gladly improve di tutorial.