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:

User clicks or types @onclick · @bind C# handler runs your method executes State changes fields get new values Blazor re-renders UI updates automatically
The Blazor loop: an event runs your C#, your C# changes state, and Blazor repaints the page — no manual DOM work.

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:

Three ways to bind C# to your page
You want to…SyntaxExample
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!