A component parameter is a public property that receives a value from the parent component.
Parameters allow you to create configurable and reusable components. In Blazor, we declare them with [Parameter] and assign them from the parent’s markup.
This data flow is fundamental in modern interface design and follows a strict pattern: One-Way Data Binding. Data flows downward, from parent to child.
The [Parameter] Attribute
To turn a normal C# class property into a parameter that can receive values from HTML, simply decorate it with the [Parameter] attribute.
Let’s revisit our user card example, but this time making it dynamic.
Definition in the Child (UserCard.razor)
<div class="card" style="border-color: @BorderColor">
<h3>@Title</h3>
<p>Age: @Age</p>
</div>
@code {
// For a property to be a parameter, it must:
// 1. Be public
// 2. Have { get; set; }
// 3. Have the [Parameter] attribute
[Parameter]
public string Title { get; set; } = "Anonymous User"; // Default value
[Parameter]
public int Age { get; set; }
[Parameter]
public string BorderColor { get; set; } = "gray";
}It’s good practice to initialize properties with default values. If the parent doesn’t send the data, the component won’t fail or show ugly empty spaces.
Usage in the Parent (Home.razor)
Now, from the parent component, we can set these values using HTML attributes that match the names of our properties.
@page "/"
<h1>System Users</h1>
<UserCard Title="Luis Llamas" BorderColor="blue" />
<UserCard Title="Ana García" Age="@(25 + 5)" />
<UserCard Title="@currentUser" Age="currentAge" />
@code {
private string currentUser = "Pedro";
private int currentAge = 40;
}Notice the difference:
- A literal
stringis written directly:Title="Luis". - For a complex expression, use
@(...):Age="@(25 + 5)". - For parameters whose type is not
string, Blazor interprets the value as C# and usually doesn’t need@:Age="currentAge". To distinguish a variable from a literal in astringparameter, we do useTitle="@currentUser".
Passing Complex Objects
In real-world (LOB) applications, we rarely pass individual properties (Name, Age, Email…). It’s more common to pass a complete object (a Model or DTO).
Blazor handles this perfectly.
The Model:
public class User
{
public string Name { get; set; }
public string Email { get; set; }
public bool IsActive { get; set; }
}The Child (UserCard.razor):
<div class="card @(UserData.IsActive ? "bg-light" : "bg-warning")">
<h4>@UserData.Name</h4>
<small>@UserData.Email</small>
</div>
@code {
[Parameter]
public User UserData { get; set; } = default!; // We receive the entire object
}The Parent:
<UserCard UserData="myUser" />
@code {
private User myUser = new User
{
Name = "Carlos",
Email = "[email protected]",
IsActive = true
};
}Required Parameters with [EditorRequired]
Sometimes, a component doesn’t make sense without a specific parameter. For example, a user card without a user.
Since .NET 6, we can use the [EditorRequired] attribute to tell Visual Studio to warn us if we forget to pass that parameter.
[Parameter, EditorRequired]
public User UserData { get; set; } = default!;If we use <UserCard /> without passing UserData, the build tools will show a warning. [EditorRequired] does not validate the value at runtime, so you should still maintain nullability and appropriate checks.
Use it when the parameter is essential for the component to function. This makes it clear what data the component requires.
Do Not Overwrite Parameters
As a general rule, do not write to a [Parameter] after the initial render. The parent may reassign it when it re-renders and overwrite your local change.
// ⛔ BAD: Modifying a parameter internally
private void Birthday()
{
// If the parent re-renders, this value will be overwritten
// with the original value from the parent.
Age++;
}In the “One-Way” flow, the owner of the data is the Parent. The Child only receives it for display.
- If the parent changes the value, the child updates automatically (
OnParametersSet). - If the child needs to change the data, it must notify the parent (through Events, which we’ll see later) so that the parent can make the change.
If you modify the parameter in the child, you will create inconsistent states and hard-to-track bugs where data mysteriously “reverts back.”
Route Parameters
Although technically a Routing topic, it’s worth mentioning that [Parameter] attributes are also used to read data from the URL.
If we have @page "/user/{Id}", we can capture that Id like this:
@page "/user/{Id}"
<h3>Viewing user: @Id</h3>
@code {
[Parameter]
public string Id { get; set; }
}Blazor is smart: seeing that the Id property matches the {Id} segment in the route, it automatically injects the value.
Summary
The [Parameter] attribute is the pipeline through which data travels in our application.
- We use
[Parameter]on public properties of the child component. - Data flows Parent -> Child.
- We can pass simple types or complex objects.
- We use
[EditorRequired]to warn that a required parameter is missing. - We do not modify parameters inside the child; we respect the single source of truth.
What if we want to pass HTML snippets or other components instead of data like strings, numbers, or objects? For example, a modal window that accepts any content.
For that, regular parameters won’t work. We need something more powerful: RenderFragments, which is the topic of our next article.