Blazor: Cascading Values

Cascading values make it possible to make values and objects available to all components without the need to pass them along explicitly.

The first rectangle on the top of this pic represents the root component. The row below it's children and the row below it their children and you could imagine this can go on for a while in a complex application.
What if we have data that all or most of all these components need. For example something that defines a visual theme for all the components in an application. For example a css class they must use when they render a button. One approach would be to pass on this information with an element attribute from component to component. But that would not be very clean not to mention very tedious to code.

Luckily there's a nice feature in Blazor that helps out in such cases called Cascading Values.

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <CascadingValue Value="@buttonClass">
            <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <LayoutView Layout="@typeof(MainLayout)">
            <p>Sorry, there's nothing at this address.</p>
@code {
    private string buttonClass = "btn-danger";

Here we are in the app root component. I'm declaring a field called buttonClass here of the type string with the value "btn-danger" which is a css class from bootstrap to make a button look dangerous and by default dangerous is red.
To make this value available for all child components we can wrap the RouteView component which take care of rendering the pages in a CascadingValue component which supplies the value that comes from the field.
Now all pages but also the children of all pages and their children etc. will have access to the value.

public class AddEmployeeDialogBase : ComponentBase
    public string BtnClass { getset; }

Here's the code-behind file for a component called AddEmployeeDialog. To apply the buttonclass we can create a string property and decorate it with the cascadingparameter attribute.

We can then just use the property in the Razor part of the component:

<button type="submit" class="btn @BtnClass">Save employee</button>

The cool thing is that now just one component uses the value but in fact all the components in the application could capture the cascading value like this and use it.
Maybe you noticed that I named the field in the root component ButtonClass and that I used btnName for the property in AddEmployeeDialog. That was deliberate to show you that the matching of the value is not done by using the name of the property but by the type of the value.
So because the value cascading down is a string, Blazor figured that the cascading value ButtonClass, which is string, had to be used on the CascadingParameter property in AddEmployeeDialog.

It is also possible to nest cascading values. Here are two in a schematic overview of a AddEmployeeDialog component rendered in an EmployeeOverView component where the AddEmployeeDialog has the CascadingParameter.

But what if both buttonClass and inputClass are strings? Then Blazor will pick the last one, the one closest in the hierarchy to the component that uses the value.

It's also possible to give each value a name and then pick a name with the CascadingParameter attribute like this:

Better still is probably to not use simple types but create a class for your cascading values. For example create a class called Theme with the ButtonClass parameter. Instead of using a string I now use an instance of the new class as the cascading value. In AddEmployeeDialog I can now also make the cascading value property of that type:

public Theme UiTheme { getset; }

And just use the ButtonClass property of the object in the class attribute of the button like this:

<button type="submit" class="btn @UiTheme.ButtonClass">Save employee</button>

One final thing about cascading values: just like binding with normal parameters Blazor will track the value for changes. So if the value of the ButtonClass property changes all components using the value will reflect the change immediately. Constantly monitoring the value will demand some resources and will potentially slow the application down. You can therefore turn the active monitoring off if you want by setting IsFixed to true when rendering the CascadingValue component.

<CascadingValue Value="@theme">

When you want to hear me explain all the things about Blazor components, please watch my Pluralsight course "Creating Blazor Components".

Tweet Post Share Update Email RSS