Web UIs with Blazor

Blazor lets you build interactive web front-ends in C# instead of JavaScript. By the end of this lesson you'll understand Blazor components in .razor files, Razor syntax, passing data with [Parameter] , two-way binding with @bind , event handlers like @onclick , the OnInitializedAsync lifecycle, dependency injection with @inject , routing with @page , the difference between Blazor Server and Blazor WebAssembly , and forms with EditForm validation.

Learn Web UIs with Blazor in our free C# course — an interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free C# course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Think of a web page as a wall built from LEGO bricks . Each Blazor component is a brick — a self-contained piece with its own shape (markup) and studs (parameters) that snap into a parent. A [Parameter] is a stud the parent presses data onto; @bind is a two-way connector so a brick and its data move together; an event like @onclick is a little switch on the brick. You assemble a whole page by clicking small, reusable bricks together — and because they're all the same C# you already know, you don't switch languages to do it.

A Blazor app is a tree of components . Each component is a .razor file mixing HTML-like markup with C# in a @code block. The component holds state (fields), and when that state changes — typically from an event handler — Blazor automatically re-renders the component and updates only the parts of the page that changed. You describe what the UI should look like for a given state; Blazor handles the DOM.

This is the same component-and-state idea behind every modern front-end framework — here it's just C# all the way down.

In Razor, an @ switches from markup into C#: @name prints a value, and @if / @foreach drive the markup.

1. Components, State, and Events

A Blazor component is a .razor file: HTML-like markup at the top, a @code block of C# below. Fields in @code are the component's state , and you display them in markup with @field . Wire a button to a method with @onclick ; when the method changes state, Blazor automatically re-renders — no manual DOM updates. Read the classic counter and note how clicking updates the displayed count.

2. Two-Way Binding with @bind

@bind connects an input to a C# field in both directions: the input shows the current value, and the user's edits flow straight back into the field. Add @bind:event="oninput" to update on every keystroke rather than when the box loses focus. Because the field is the single source of truth, anything else that displays it updates live too.

Your turn. This toggle just needs its click wired up and the boolean flipped. Fill in the two ___ blanks using the hints.

3. Reusable Components with [Parameter]

Components become reusable when a parent can pass data into them. Mark a public property with [Parameter] and the parent sets it like an HTML attribute: . This is how you build a small component once and render it many times with different data — cards, list rows, badges, and so on.

Now you try. Finish this reusable price tag by exposing both fields as parameters so a parent can set them. Fill in the two ___ blanks:

4. Dependency Injection and Lifecycle

Components often need services — an HttpClient to call an API, a custom data service. @inject asks the DI container for one and assigns it to a property. To load data, override OnInitializedAsync , which runs once when the component initializes and lets you await the work; when it finishes, Blazor re-renders with the results. Show a "Loading..." placeholder until the data arrives.

Blazor runs your components in one of two hosting models, and the component code looks almost identical in both:

Because the programming model is shared, you can often start with one model and switch later with minimal changes.

Here's a realistic form that ties the lesson together. An EditForm binds to a model; a DataAnnotationsValidator turns [Required] and [EmailAddress] attributes into live validation; InputText uses @bind-Value ; and OnValidSubmit only fires once the input is valid. ValidationMessage shows the error next to each field.

Validation, binding, and submission are all C# — the same skills from the rest of the course, now driving a web form.

For most UI logic, yes — you write components in C#. You can still call JavaScript when you need a browser API or a JS library (via JS interop), but day-to-day interactivity is C#.

Q: Should I choose Blazor Server or WebAssembly?

Server gives a tiny initial download and direct server access but needs a live SignalR connection. WebAssembly runs in the browser, works offline, and feels instant after a larger first load. The component code is nearly identical either way.

Q: What's the difference between @bind and @onclick ?

@bind creates a two-way data link between an input and a C# value. @onclick (and other @on... handlers) runs a C# method in response to an event, after which the component re-renders.

Q: Why use OnInitializedAsync instead of the constructor for loading data?

The constructor can't await , and parameters aren't set yet. OnInitializedAsync runs after the component is set up, can await async calls, and triggers a re-render when the data is ready.

No blanks this time — just a brief and an outline. Build a component with bound bill and tipPercent inputs and a computed Tip property that updates live as the user types. For a bonus, also show the grand total. Run it and watch the tip recalculate on every keystroke.

Practice quiz

What does Blazor let you build that previously required JavaScript?

  • Interactive web user interfaces written in C#
  • Mobile device drivers
  • SQL database engines
  • Operating system kernels

Answer: Interactive web user interfaces written in C#. Blazor lets you build interactive web UIs using C# and Razor components instead of writing the UI logic in JavaScript.

What file extension do Blazor components use?

  • .xaml
  • .cshtml
  • .razor
  • .blazor

Answer: .razor. Blazor components are written in .razor files, which combine Razor markup (HTML plus C#) with component logic.

Which attribute marks a C# property as a component parameter that a parent can set?

The [Parameter] attribute exposes a public property so a parent component can pass a value into the child, like an attribute in markup.

In Razor markup, how do you wire a button click to a C# method named Increment?

  • click={Increment}
  • @onclick="Increment"
  • bind:click=Increment
  • onclick=Increment

Answer: @onclick="Increment". Razor event handlers use the @on prefix; @onclick="Increment" calls the C# method when the button is clicked.

What does @bind do on an input element?

  • Sends the value to a database
  • Deletes the element
  • Adds CSS classes only
  • Creates a two-way binding between the input and a C# field/property

Answer: Creates a two-way binding between the input and a C# field/property. @bind sets up two-way data binding: the input shows the C# value and writes user edits back into that field or property.

Which lifecycle method is the right place to load data asynchronously when a component initializes?

  • OnInitializedAsync()
  • Render()
  • Dispose()
  • Main()

Answer: OnInitializedAsync(). OnInitializedAsync() runs when the component is first initialized and is the standard place to await data loading such as an API call.

How do you request a service via dependency injection inside a .razor component?

  • @page the service
  • @inject SomeService Name
  • @using the service
  • new Service()

Answer: @inject SomeService Name. The @inject directive asks the DI container for a service and assigns it to a property, e.g. @inject HttpClient Http.

What is the key difference between Blazor Server and Blazor WebAssembly?

  • Server uses C# while WebAssembly uses Java
  • WebAssembly cannot render HTML
  • There is no difference
  • Server runs C# on the server with UI updates over a SignalR connection; WebAssembly runs the .NET code in the browser

Answer: Server runs C# on the server with UI updates over a SignalR connection; WebAssembly runs the .NET code in the browser. Blazor Server executes component logic on the server and pushes UI diffs to the browser over SignalR; Blazor WebAssembly downloads a .NET runtime and runs the C# directly in the browser.

Which directive at the top of a component defines its route, e.g. /counter?

  • @route
  • @url
  • @page "/counter"
  • @map

Answer: @page "/counter". @page "/counter" sets the route template so navigating to /counter renders that routable component.

What does an EditForm with DataAnnotationsValidator provide?

  • Automatic database migrations
  • Model-based form validation that shows messages when input is invalid
  • Image compression
  • Server logging only

Answer: Model-based form validation that shows messages when input is invalid. EditForm binds to a model and, with DataAnnotationsValidator, validates it against data-annotation attributes, surfacing validation messages in the UI.