Download Sample Code

Cascading Parameter

In Blazor, cascading parameters enable developers to pass data across multiple levels of a component tree without explicitly passing it through each intermediate component (prop drilling). This tutorial introduces the following aspects of using cascading parameters:

  • Different approaches to using cascading parameters.
  • Passing and updating a parameter with the root level technique.
  • Passing, updating, and overriding a parameter with the CascadingValue component

Different Approaches to Using Cascading Parameters

In Blazor, cascading parameters can be implemented in 2 primary ways: registering them at the root level in Program.cs (root-level technique) or using the CascadingValue component within specific parts of the component tree. Each approach has distinct characteristics, as outlined in the comparison table below:

Aspect Root Level Technique CascadingValue Component
Overriding Parameter Value No Yes
Refresh UI When the Value Changes Automatically Manual
Declaration Location Program.cs Any Component
  • Root-Level Technique: By providing a cascading parameter in Program.cs, it becomes available to all components in the app. This method automatically updates the UI when the value changes but doesn’t allow overriding at lower levels.
  • CascadingValue Component: Using CascadingValue within a component allows for more control, enabling you to override the parameter in specific branches of the tree. However, UI updates require manual triggering (e.g., via StateHasChanged).
Do not use the root level technique as a way to register a singleton/scoped service. The root level cascading parameter is designed only for passing parameters, not for passing services. If you need a service, use the dependency injection feature instead.

Passing and Updating a Parameter with the Root Level Technique

You can register cascading parameters in Program.cs to provide site-wide data, it is particularly effective for scenarios like theme settings or account information, where a single value needs to be shared across the entire app.

  1. Define the parameter model (if any). Keep in mind that while this example uses a class (RootLevelSampleModel) as the cascading parameter, you're not limited to classes. The root level technique also supports registering struct-typed values, such as string, int, bool, and more.
public class RootLevelSampleModel
{
    public string Message { get; set; } = "";
}
  1. Register Parameters in Program.cs.
builder.Services.AddCascadingValue<RootLevelSampleModel>(sp => new RootLevelSampleModel
{
    Message = "Hello Blazor School!"
});

To register 2 parameters of the same type, use the Name parameter to differentiate them:

builder.Services.AddCascadingValue&lt;RootLevelSampleModel&gt;(&quot;Variant2&quot;, sp =&gt; new RootLevelSampleModel
{
    Message = &quot;Hello Blazor School! (Variant2)&quot;
});
  1. Access parameter in a component
<div>Message: @Sample?.Message</div>
<div>Variant2 Message: @SampleVariant2?.Message</div>

@code {
    [CascadingParameter]
    public RootLevelSampleModel? Sample { get; set; }

    [CascadingParameter(Name = "Variant2")]
    public RootLevelSampleModel? SampleVariant2 { get; set; }
}

Update Root Level Parameter

  1. Define the parameter model: In the parameter model, add CascadingValueSource<T> where T is the parameter model itself.
public class RootLevelUpdatingModel
{
    public string Message { get; set; } = "";
    public CascadingValueSource<RootLevelUpdatingModel>? Source { get; set; }
}
  1. Register in Program.cs.
builder.Services.AddCascadingValue(sp =>
{
    var value = new RootLevelUpdatingModel()
    {
        Message = "Hello Blazor School! (With Notifying)",
    };

    value.Source = new CascadingValueSource<RootLevelUpdatingModel>(value, false);

    return value.Source;
});
  1. Update the parameter and call NotifyChangeAsync from CascadingValueSource.
<h3>Component2 (Level 1)</h3>
<div>Message: @Sample?.Message</div>
<button type="button" @onclick="UpdateValueAsync">Update Value</button>

@code {
    [CascadingParameter]
    public RootLevelUpdatingModel? Sample { get; set; }

    public async Task UpdateValueAsync()
    {
        if (Sample is not null && Sample.Source is not null)
        {
            Sample.Message = "Overridden from Component2";
            await Sample.Source.NotifyChangedAsync();
        }
    }
}

Passing, Updating, and Overriding a Parameter with the CascadingValue Component

The CascadingValue component allows you to pass parameters across a component tree, with the added flexibility of updating and overriding them at different levels. This technique is particularly useful for scenarios like multilingual websites, where different sections might display distinct languages simultaneously.

  1. Define the parameter model (optional). While you can use simple types like string or int, a class provides more structure for complex data.
public class UsingCascadingValueModel
{
    public string Message { get; set; } = "";
}
  1. Pass the Parameter Using CascadingValue in an ancestor component.
<h3>Ancestor (Level 0)</h3>
<CascadingValue Value="Model" IsFixed="true">
    <Component1 />
</CascadingValue>

@code {
    public UsingCascadingValueModel Model { get; set; } = new()
    {
        Message = "Hello from SimpleCascadingValueExample"
    };
}

In this example, we are not updating the parameter, so we set IsFixed to true. Setting IsFixed to true will not allow the parameter to be updated but will yield better performance.

  1. Access the parameter in a descendant component.
<h3>Component1 (Level 0)</h3>
<div>Message: @Sample?.Message</div>

@code {
    [CascadingParameter]
    public UsingCascadingValueModel? Sample { get; set; }
}

In case you are passing multiple parameters of the same type, set a name when passing them with CascadingValue:

<CascadingValue Value="Model" IsFixed="true" Name="blazorschool_parameter">
    <!-- ... -->
</CascadingValue>

Then, in your descendant component, use the name to differentiate the parameters:

@code {
    [CascadingParameter(Name = "blazorschool_parameter")]
    public UsingCascadingValueModel? Sample { get; set; }
}

Update Parameter

A parameter passed by CascadingValue can be updated at any level in the hierarchy.

  1. Define the parameter and update logic in the ancestor component. Pass both the parameter and the component instance (this) using nested CascadingValue.
<CascadingValue Value="this">
    <CascadingValue Value="Model">
        <Component1 />
    </CascadingValue>
</CascadingValue>

@code {
    public UsingCascadingValueModel Model { get; set; } = new()
    {
        Message = "Hello from UpdateCascadingValueExample"
    };

    public void UpdateModelMessage(string message)
    {
        Model.Message = message;
        StateHasChanged();
    }
}
  1. Update the parameter in a descendant component. Access both the parameter and the ancestor instance to call the update method.
<h3>Component2 (level 1)</h3>
<div>Message: @Sample?.Message</div>
<button type="button" @onclick="UpdateValueAsync">Update Value</button>

@code {
    [CascadingParameter]
    public UsingCascadingValueModel? Sample { get; set; }

    [CascadingParameter]
    public UpdateCascadingValueExample? Source { get; set; }

    public async Task UpdateValueAsync()
    {
        if (Source is not null)
        {
            Source.UpdateModelMessage("Update from Component2");
        }
    }
}

Overriding Parameter

A parameter passed by CascadingValue can be overridden to have different values in different branches. Furthermore, a descendant component can override the parameter value in any ancestor component.

We will set up the example with 4 levels: OverrideCascadingValueExample as the ancestor component, Component1 as Level 0, Component2 as Level 1, and Component3 as Level 2. The parameter will be passed from OverrideCascadingValueExample and will be overridden in Component2, and then updated in Component3.

  1. Define the parameter and update logic in the ancestor component. Pass the component instance and parameter using nested CascadingValue.
<CascadingValue Value="this">
    <CascadingValue Value="Model">
        <Component1 />
    </CascadingValue>
</CascadingValue>

@code {
    public UsingCascadingValueModel Model { get; set; } = new()
        {
            Message = "Hello from OverrideCascadingValueExample"
        };

    public void UpdateModel(string message)
    {
        Model.Message = message;
        StateHasChanged();
    }
}
  1. In the descendant component where you want to override the parameter, declare the parameter and the update logic. Pass the current instance (this) and the overridden parameter using CascadingValue.
<h3>Component2 (level 1)</h3>
<div>Message: @OverridingSample.Message</div>
<CascadingValue Value="this">
    <CascadingValue Value="OverridingSample">
        <Component3 />
    </CascadingValue>
</CascadingValue>

@code {
    public UsingCascadingValueModel OverridingSample { get; set; } = new UsingCascadingValueModel()
    {
        Message = "Overridden from Component2"
    };

    public void UpdateModel(string message)
    {
        OverridingSample.Message = message;
        StateHasChanged();
    }
}
  1. Update the parameter from a descendant component. Access both the overridden parameter and ancestor instances to update either.
<h3>Component3 (level 2)</h3>
<div>Message: @Sample?.Message</div>
<button type="button" @onclick="UpdateAtLevel1">Update at level 1</button>
<button type="button" @onclick="UpdateAtRoot">Update at root</button>

@code {
    [CascadingParameter]
    public UsingCascadingValueModel? Sample { get; set; }

    [CascadingParameter]
    public Component2? Component2 { get; set; }

    [CascadingParameter]
    public OverrideCascadingValueExample? Root { get; set; }

    public void UpdateAtLevel1()
    {
        Component2?.UpdateModel("Updated from Component3");
    }

    public void UpdateAtRoot()
    {
        Root?.UpdateModel("Updated from Component3");
    }
}
BLAZOR SCHOOL
Designed and built with care by our dedicated team, with contributions from a supportive community. We strive to provide the best learning experience for our users.
Docs licensed CC-BY-SA-4.0
Copyright © 2021-2025 Blazor School
An unhandled error has occurred. Reload 🗙