blazor-one-way-binding

One-way binding in Blazor: displaying data in the UI

  • 4 min

The one-way binding is the flow of data in a single direction, from C# code to the rendered UI.

In the previous article we captured what the user does through events. Now we are going to display values of variables, properties, and expressions in the HTML.

We call this One-Way Binding. It is called this because the information flow travels in one direction: From C# code to HTML.

If the variable changes in the code, the HTML updates. But if the user interacts with the HTML (for example, typing in an input), the variable does not know about it (yet).

Binding text content

The most basic form of binding is printing the value of a variable inside an HTML tag. As we saw in the syntax section, this is done with the @ symbol.

<h3>User Profile</h3>

<p>Name: @UserName</p>
<p>Level: @CalculateLevel()</p>
<p>Last Login: @LastLogin.ToShortDateString()</p>

@code {
    private string UserName = "Luis";
    private int Score = 1500;
    private DateTime LastLogin = DateTime.Now;

    private int CalculateLevel()
    {
        return Score / 100;
    }
}
Copied!

Every time Blazor renders this component, it will evaluate @UserName and substitute that expression with the current value of the string.

Remember: Blazor automatically renders when a UI event occurs (like a click). If you change UserName in an @onclick method, the <p> paragraph will update automatically.

Binding HTML attributes

In addition to painting text between tags, we can use values in HTML attributes.

This is essential for images, links, and CSS classes.

<img src="@AvatarUrl" alt="Photo of @UserName" />

<a href="/user/@UserId">View Profile</a>

<div style="background-color: @BgColor; width: @(Progress)%">
    @Progress %
</div>

@code {
    private string AvatarUrl = "/img/default-user.png";
    private string UserName = "Luis";
    private int UserId = 42;
    private string BgColor = "green";
    private int Progress = 75;
}
Copied!

Notice that we don’t need special quotes or weird syntax like v-bind or ng-bind. We simply use C# inside the attribute.

The special case of boolean attributes

In HTML, there are attributes that work by their mere presence, not by their value. Classic examples are disabled, readonly, checked, or selected.

  • Classic HTML: <input disabled> (it is disabled).
  • Classic HTML: <input> (it is enabled).

If we tried to do this the old way: <input disabled="@isDisabled"> We might think that if isDisabled is false, the disabled="false" attribute would make the input work. Wrong. In HTML, disabled="false" still disables the input because the attribute exists.

Blazor handles boolean attributes specially.

If you bind an attribute to a bool variable, Blazor will remove the attribute entirely from the DOM if the value is false, and add it if it is true.

<label>
    <input type="checkbox" @onchange="ToggleEdit" /> Edit
</label>

<input type="text" value="Test text" readonly="@IsReadOnly" />

<button class="btn btn-primary" disabled="@IsSaving">
    @(IsSaving ? "Saving..." : "Save")
</button>

@code {
    private bool IsReadOnly = true;
    private bool IsSaving = false;

    private void ToggleEdit()
    {
        IsReadOnly = !IsReadOnly;
    }
}
Copied!

This feature saves us from writing a lot of ugly conditional logic inside the HTML.

Dynamic CSS classes

Managing CSS classes dynamically is a daily task in frontend development (adding a red border if there is an error, a gray background if inactive).

Although we can concatenate strings, the cleanest way is to use the C# ternary conditional expression inside the class attribute.

<div class="alert @(IsError ? "alert-danger" : "alert-success")">
    @Message
</div>

<button class="btn @btnColor @(IsActive ? "active" : "")">
    Click me
</button>

@code {
    private bool IsError = false;
    private string Message = "Operation successful";
    private bool IsActive = true;
    private string btnColor = "btn-primary";
}
Copied!

For very complex class logic, it is recommended to create a read-only property in the @code block that builds the class string, keeping the HTML clean.

Limitations of one-way binding

It is important to understand that this is a “projection”. If we do this:

<input value="@UserName" />
Copied!
  1. The input will show the initial value of UserName (“Luis”).
  2. If the user deletes “Luis” and types “Ana”, the C# variable UserName WILL STILL BE “Luis”.
  3. There is no connection back.

If we want the variable to update when the user types, we need to combine One-Way Binding (value="@...") with an event (@onchange="...") that updates the variable.