Core Blazor Data Binding - Microsoft Learn
Core Blazor Data Binding - Microsoft Learn
This article explains data binding features for Razor components and DOM elements in
Blazor apps.
Razor components provide data binding features with the @bind Razor directive attribute
with a field, property, or Razor expression value.
When an <input> element loses focus, its bound field or property is updated.
Pages/Bind.razor :
razor
@page "/bind"
<p>
<input @bind="inputValue" />
</p>
<p>
<input @bind="InputValue" />
</p>
<ul>
<li><code>inputValue</code>: @inputValue</li>
<li><code>InputValue</code>: @InputValue</li>
</ul>
@code {
private string? inputValue;
The text box is updated in the UI only when the component is rendered, not in response to
changing the field's or property's value. Since components render themselves after event
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 1/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
handler code executes, field and property updates are usually reflected in the UI
immediately after an event handler is triggered.
As a demonstration of how data binding composes in HTML, the following example binds
the InputValue property to the second <input> element's value and onchange attributes
(change ). The second <input> element in the following example is a concept
demonstration and isn't meant to suggest how you should bind data in Razor components.
Pages/BindTheory.razor :
razor
@page "/bind-theory"
<p>
<label>
Normal Blazor binding:
<input @bind="InputValue" />
</label>
</p>
<p>
<label>
Demonstration of equivalent HTML binding:
<input value="@InputValue"
@onchange="@((ChangeEventArgs __e) => InputValue =
__e?.Value?.ToString())" />
</label>
</p>
<p>
<code>InputValue</code>: @InputValue
</p>
@code {
private string? InputValue { get; set; }
}
When the BindTheory component is rendered, the value of the HTML demonstration
<input> element comes from the InputValue property. When the user enters a value in the
text box and changes element focus, the onchange event is fired and the InputValue
property is set to the changed value. In reality, code execution is more complex because
@bind handles cases where type conversions are performed. In general, @bind associates
the current value of an expression with the value attribute of the <input> and handles
changes using the registered handler.
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 2/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
(input ) is triggered. Unlike the onchange event (change ), which fires when the element
loses focus, oninput (input ) fires when the value of the text box changes.
Page/BindEvent.razor :
razor
@page "/bind-event"
<p>
<input @bind="InputValue" @bind:event="oninput" />
</p>
<p>
<code>InputValue</code>: @InputValue
</p>
@code {
private string? InputValue { get; set; }
}
To execute asynchronous logic after binding, use @bind:after="{EVENT}" with a DOM event
for the {EVENT} placeholder. An assigned C# method isn't executed until the bound value
is assigned synchronously.
search results.
razor
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 3/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
@code {
private string? searchText;
private string[]? searchResult;
Additional examples
Pages/BindAfter.razor :
razor
@page "/bind-after"
@using Microsoft.AspNetCore.Components.Forms
<h2>Elements</h2>
<h2>Components</h2>
@code {
private string text = "";
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 4/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
For more information on the InputText component, see ASP.NET Core Blazor forms and
input components.
Examples
Pages/BindGetSet.razor :
razor
@page "/bind-get-set"
@using Microsoft.AspNetCore.Components.Forms
<h2>Elements</h2>
<h2>Components</h2>
@code {
private string text = "";
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 5/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
For more information on the InputText component, see ASP.NET Core Blazor forms and
input components.
For another example use of @bind:get and @bind:set , see the Bind across more than two
components section later in this article.
❌ Consider the following dysfunctional approach for two-way data binding using an
event handler:
razor
<p>
<input value="@inputValue" @oninput="OnInput" />
</p>
<p>
<code>inputValue</code>: @inputValue
</p>
@code {
private string? inputValue;
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 6/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
The OnInput event handler updates the value of inputValue to Long! after a fourth
character is provided. However, the user can continue adding characters to the element
value in the UI. The value of inputValue isn't bound back to the element's value with each
keystroke. The preceding example is only capable of one-way data binding.
The reason for this behavior is that Blazor isn't aware that your code intends to modify the
value of inputValue in the event handler. Blazor doesn't try to force DOM element values
and .NET variable values to match unless they're bound with @bind syntax. In earlier
versions of Blazor, two-way data binding is implemented by binding the element to a
property and controlling the property's value with its setter. In ASP.NET Core 7.0 or later,
@bind:get / @bind:set modifier syntax is used to implement two-way data binding, as the
✔️Consider the following correct approach using @bind:get / @bind:set for two-way data
binding:
razor
<p>
<input @bind:event="oninput" @bind:get="inputValue" @bind:set="OnInput" />
</p>
<p>
<code>inputValue</code>: @inputValue
</p>
@code {
private string? inputValue;
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 7/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
Using @bind:get / @bind:set modifiers both controls the underlying value of inputValue via
@bind:set and binds the value of inputValue to the element's value via @bind:get . The
preceding example demonstrates the correct approach for implementing two-way data
binding.
Pages/DecimalBinding.razor :
razor
@page "/decimal-binding"
@using System.Globalization
<p>
<label>
Decimal value (±0.000 format):
<input @bind="DecimalValue" />
</label>
</p>
<p>
<code>decimalValue</code>: @decimalValue
</p>
@code {
private decimal decimalValue = 1.1M;
private NumberStyles style =
NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
private CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 8/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
7 Note
Two-way binding to a property with get / set accessors requires discarding the Task
returned by EventCallback.InvokeAsync. For two-way data binding, we recommend
using @bind:get / @bind:set modifiers. For more information, see the
@bind:get / @bind:set guidance in the earlier in this article.
Pages/BindMultipleInput.razor :
razor
@page "/bind-multiple-input"
<p>
<label>
Select one or more cars:
<select @onchange="SelectedCarsChanged" multiple>
<option value="audi">Audi</option>
<option value="jeep">Jeep</option>
<option value="opel">Opel</option>
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 9/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
<option value="saab">Saab</option>
<option value="volvo">Volvo</option>
</select>
</label>
</p>
<p>
Selected Cars: @string.Join(", ", SelectedCars)
</p>
<p>
<label>
Select one or more cities:
<select @bind="SelectedCities" multiple>
<option value="bal">Baltimore</option>
<option value="la">Los Angeles</option>
<option value="pdx">Portland</option>
<option value="sf">San Francisco</option>
<option value="sea">Seattle</option>
</select>
</label>
</p>
<span>
Selected Cities: @string.Join(", ", SelectedCities)
</span>
@code {
public string[] SelectedCars { get; set; } = new string[] { };
public string[] SelectedCities { get; set; } = new[] { "bal", "sea" };
For information on how empty strings and null values are handled in data binding, see
the Binding <select> element options to C# object null values section.
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 10/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
There's no sensible way to represent a <select> element option value as a C# object null
value, because:
HTML attributes can't have null values. The closest equivalent to null in HTML is
absence of the HTML value attribute from the <option> element.
When selecting an <option> with no value attribute, the browser treats the value as
the text content of that <option> 's element.
The Blazor framework doesn't attempt to suppress the default behavior because it would
involve:
The most plausible null equivalent in HTML is an empty string value . The Blazor
framework handles null to empty string conversions for two-way binding to a <select> 's
value.
Unparsable values
When a user provides an unparsable value to a databound element, the unparsable value is
automatically reverted to its previous value when the bind event is triggered.
Consider the following component, where an <input> element is bound to an int type
with an initial value of 123 .
Pages/UnparsableValues.razor :
razor
@page "/unparseable-values"
<p>
<input @bind="inputValue" />
</p>
<p>
<code>inputValue</code>: @inputValue
</p>
@code {
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 11/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
By default, binding applies to the element's onchange event. If the user updates the value
of the text box's entry to 123.45 and changes the focus, the element's value is reverted to
123 when onchange fires. When the value 123.45 is rejected in favor of the original value
For the oninput event ( @bind:event="oninput" ), a value reversion occurs after any
keystroke that introduces an unparsable value. When targeting the oninput event with an
int -bound type, a user is prevented from typing a dot ( . ) character. A dot ( . ) character is
immediately removed, so the user receives immediate feedback that only whole numbers
are permitted. There are scenarios where reverting the value on the oninput event isn't
ideal, such as when the user should be allowed to clear an unparsable <input> value.
Alternatives include:
Don't use the oninput event. Use the default onchange event, where an invalid value
isn't reverted until the element loses focus.
Bind to a nullable type, such as int? or string and either use @bind:get / @bind:set
modifiers (described earlier in this article) or bind to a property with custom get and
set accessor logic to handle invalid entries.
Use a form validation component, such as InputNumber<TValue> or
InputDate<TValue>. Form validation components provide built-in support to manage
invalid inputs. Form validation components:
Permit the user to provide invalid input and receive validation errors on the
associated EditContext.
Display validation errors in the UI without interfering with the user entering
additional webform data.
Format strings
Data binding works with a single DateTime format string using @bind:format="{FORMAT
STRING}" , where the {FORMAT STRING} placeholder is the format string. Other format
expressions, such as currency or number formats, aren't available at this time but might be
added in a future release.
Pages/DateBinding.razor :
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 12/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
razor
@page "/date-binding"
<p>
<label>
<code>yyyy-MM-dd</code> format:
<input @bind="startDate" @bind:format="yyyy-MM-dd" />
</label>
</p>
<p>
<code>startDate</code>: @startDate
</p>
@code {
private DateTime startDate = new(2020, 1, 1);
}
In the preceding code, the <input> element's field type ( type attribute) defaults to text .
C#
Specifying a format for the date field type isn't recommended because Blazor has built-in
support to format dates. In spite of the recommendation, only use the yyyy-MM-dd date
format for binding to function correctly if a format is supplied with the date field type:
razor
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 13/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
You can't implement chained binds with @bind syntax in the child component. An event
handler and value must be specified separately to support updating the property in the
parent from the child component.
The parent component still leverages the @bind syntax to set up the databinding with the
child component.
EventCallback.InvokeAsync invokes the delegate associated with the binding with the
provided argument and dispatches an event notification for the changed property.
Shared/ChildBind.razor :
razor
@code {
private Random r = new();
[Parameter]
public int Year { get; set; }
[Parameter]
public EventCallback<int> YearChanged { get; set; }
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 14/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
}
}
For more information on events and EventCallback<TValue>, see the EventCallback section
of the ASP.NET Core Blazor event handling article.
In the following Parent1 component, the year field is bound to the Year parameter of the
child component. The Year parameter is bindable because it has a companion YearChanged
event that matches the type of the Year parameter.
Pages/Parent1.razor :
razor
@page "/parent-1"
<h1>Parent Component</h1>
@code {
private Random r = new();
private int year = 1979;
Component parameter binding can also trigger @bind:after events. In the following
example, the YearUpdated method executes asynchronously after binding the Year
component parameter.
razor
@code {
...
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 15/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
razor
Shared/PasswordEntry.razor :
razor
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 16/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
@code {
private bool showPassword;
private string? password;
[Parameter]
public string? Password { get; set; }
[Parameter]
public EventCallback<string> PasswordChanged { get; set; }
await PasswordChanged.InvokeAsync(password);
}
Pages/PasswordBinding.razor :
razor
@page "/password-binding"
<h1>Password Binding</h1>
<p>
<code>password</code>: @password
</p>
@code {
private string password = "Not set";
}
When the PasswordBinding component is initially rendered, the password value of Not set
is displayed in the UI. After initial rendering, the value of password reflects changes made
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 17/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
7 Note
The preceding example binds the password one-way from the child PasswordEntry
component to the parent PasswordBinding component. Two-way binding isn't a
requirement in this scenario if the goal is for the app to have a shared password entry
component for reuse around the app that merely passes the password to the parent.
For an approach that permits two-way binding without writing directly to the child
component's parameter, see the NestedChild component example in the Bind across
more than two components section of this article.
Perform checks or trap errors in the handler. The following revised PasswordEntry
component provides immediate feedback to the user if a space is used in the password's
value.
Shared/PasswordEntry.razor :
razor
@code {
private bool showPassword;
private string? password;
private string? validationMessage;
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 18/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
[Parameter]
public string? Password { get; set; }
[Parameter]
public EventCallback<string> PasswordChanged { get; set; }
return Task.CompletedTask;
}
else
{
validationMessage = string.Empty;
return PasswordChanged.InvokeAsync(password);
}
}
razor
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 19/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
A common and recommended approach is to only store the underlying data in the parent
component to avoid any confusion about what state must be updated, as shown in the
following example.
Pages/Parent2.razor :
razor
@page "/parent-2"
<h1>Parent Component</h1>
<p>
<button @onclick="ChangeValue">Change from Parent</button>
</p>
@code {
private string parentMessage = "Initial value set in Parent";
Shared/NestedChild.razor :
razor
<p>
<button @onclick="ChangeValue">Change from Child</button>
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 20/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
</p>
<NestedGrandchild @bind-GrandchildMessage:get="ChildMessage"
@bind-GrandchildMessage:set="ChildMessageChanged" />
</div>
@code {
[Parameter]
public string? ChildMessage { get; set; }
[Parameter]
public EventCallback<string> ChildMessageChanged { get; set; }
Shared/NestedGrandchild.razor :
razor
<p>
<button @onclick="ChangeValue">Change from Grandchild</button>
</p>
</div>
@code {
[Parameter]
public string? GrandchildMessage { get; set; }
[Parameter]
public EventCallback<string> GrandchildMessageChanged { get; set; }
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 21/22
8/3/23, 4:22 PM ASP.NET Core Blazor data binding | Microsoft Learn
For an alternative approach suited to sharing data in memory and across components that
aren't necessarily nested, see ASP.NET Core Blazor state management.
Additional resources
Parameter change detection and additional guidance on Razor component rendering
ASP.NET Core Blazor forms and input components
Binding to radio buttons in a form
Binding InputSelect options to C# object null values
ASP.NET Core Blazor event handling: EventCallback section
Blazor samples GitHub repository (dotnet/blazor-samples)
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-7.0 22/22