Previously, you set up ClinicApp, toured the project structure, and built your
first component — PatientCard.razor, with
Name and Age parameters shown on Home.razor.
So far, everything we've built has been a bit like a poster on a wall: nice to look at, but it doesn't do anything. In this part, we change that. By the end, you'll have a page that reacts when you click a button and echoes text back as you type. This is the moment Blazor starts to feel alive.
A waiting room counter
Imagine the front desk of our clinic. Every time a patient checks in, the receptionist adds
one to a tally. Let's build exactly that on Home.razor: a number on screen, and
a button that bumps it up. Open Home.razor and make it look like this (you can
keep your PatientCard lines from Part 3 below it if you like):
@page "/"
@rendermode InteractiveServer
<h2>Waiting room</h2>
<p>Patients waiting right now: <strong>@waiting</strong></p>
<button @onclick="AddPatient">Check in a patient</button>
@code {
private int waiting;
private void AddPatient()
{
waiting++;
}
}
Two new things here. The line @rendermode InteractiveServer tells current
Blazor (.NET 10) that this page responds to events — that's all you need to know for now;
the full story comes in
Part 12. And
@onclick="AddPatient" wires the button to a C# method. Not JavaScript —
plain C#, running in the same file.
Run the app and click the button. The number climbs: 1, 2, 3. Notice what you didn't write: no code that finds the paragraph and updates its text. You changed a field, and the page caught up on its own.
What just happened?
Every click sends Blazor around a little loop, and understanding it will carry you through the rest of this series:
First, the event fires — you clicked. Second, Blazor runs your
handler, the AddPatient method. Third, the handler changes
state — the waiting field ticks up by one. Fourth, Blazor
re-renders: it works out which bits of the page depend on the changed state
and updates just those bits. Then it sits quietly and waits for the next event.
Event, handler, state, re-render. That's the heartbeat of every interactive Blazor page, from this little counter to a full patient dashboard.
Two-way binding: text that echoes back
The counter is one-way traffic: your C# state flows out to the page. But what about the other
direction — the user types something, and you want it back in a C# variable? That's
two-way binding, and Blazor gives it to you with a single directive:
@bind. Try adding this below the button:
<p>Hello, @greeting!</p>
<input @bind="greeting" />
@code {
private string greeting = "there";
}
Type your name in the box, then click away or press Tab. The paragraph updates to greet you.
The greeting field and the input are now tied together: change one, and the
other follows. No event handler, no assignment — @bind does both directions
for you.
Tip: By default, @bind updates when the input loses focus.
Want it to update on every keystroke instead? Add
@bind:event="oninput" to the input, and the greeting will change live as
you type. We'll lean on this trick for live search in the next part.
The three flavors, side by side
You've now met all three ways Razor connects your C# to the page. Here they are in one place:
| You want to… | Syntax | Example |
|---|---|---|
| Show a value | @variable | <p>@waiting</p> |
| React to an event | @onclick | <button @onclick="AddPatient"> |
| Bind both ways | @bind | <input @bind="greeting" /> |
That little table covers a surprising amount of everyday Blazor. Most pages you'll ever write are just these three moves, arranged thoughtfully.
Note: A common early stumble — passing an argument to a handler. Writing
@onclick="Remove(patient)" won't work; that tries to call the
method while the page renders. Wrap it in a lambda instead:
@onclick="() => Remove(patient)". Read it as "when clicked, then
call Remove with this patient."
Where we're headed
A counter and a greeting are lovely warm-ups, but a clinic runs on real data: lists of
patients, shown, filtered, and searched. In
Part 5, we'll create a proper
Patient model, seed a list of them, and render the whole waiting room with a
loop — plus a live search box powered by the @bind:event trick you just
learned. See you there!