Blazor Client: multiple root components

Blazor Client: multiple root components

In Blazor Client (i.e. WASM) it's possible to have multiple root components on the same page.
This is possible with the WebAssemblyHostBuilder.RootComponents collection.

Let's play a bit and try it.

First, from Visual Studio, create a new Blazor client application:

  • choose the Blazor WebAssembly template:
  • no ASP.NET Core backend is necessary:

Now, let's modify a couple of CSS to allow the visualization of multiple root components on the page:

  • in Shared/MainLayout.razor.css, change the .sidebar.height from 100vh to 50vh:
    .sidebar {
      width: 250px;
      height: 50vh;
      position: sticky;
      top: 0;
  • in Shared/NavMenu.razor.css, change the .nav-scrollable.height from calc(100vh - 3.5rem) to calc(50vh - 3.5rem):
    .nav-scrollable {
        /* Allow sidebar to scroll for tall menus */
        height: calc(50vh - 3.5rem);
        overflow-y: auto;
  • running the app, we should see the usual UI using only the top-half of the page:

Let's add now the new root component to the solution:

  • start adding a SecondApp.razor file and pasting the following content:
    @using BlazorApp1.Pages
    <Counter />
  • add a reference to component to wwwroot/index.html:
        <div id="app">...</div>
        <div id="secondApp">
      	  <div>Loading second app...</div>
        <div id="blazor-error-ui">...</div>
        <script src="_framework/blazor.webassembly.js"></script>
  • in Program.cs add a binding between the SecondApp root component and the secondApp style:
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
  • running the app, we will see the new app root:

Now: the two counter components are two different instances. Let's suppose instead that we want to share state:

  • we could start modifying Pages/Counter.razor, making the currentCount variable static:
    private static int currentCount = 0;
  • the problem is that clicking on the first Counter component, the static variable is incremented, but the second instance of the Counter component is not automatically updated. I have followed this blog post: 3 Ways to Communicate Between Components in Blazor.
  • add an AppState.cs file, with the following content:
    public class AppState
      private int _currentCount = 0;
      public int CurrentCount
        get => _currentCount;
            _currentCount = value;
        public event Action? OnChange;
        private void NotifyStateChanged() => OnChange?.Invoke();
  • in Program.cs add a reference to this singleton:
    builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
  • modify Pages/Counter.razor injecting the AppState service, un-subscribing to the notification events, and replacing references to the Counter property:
    @page "/counter"
    @inject AppState AppState
    <p role="status">Current count: @AppState.CurrentCount</p>
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    @code {
      //private static int currentCount = 0;
      protected override void OnInitialized()
        AppState.OnChange += StateHasChanged;
      public void Dispose()
        AppState.OnChange -= StateHasChanged;
      private void IncrementCount()
  • running the app now, the state of the two instances will be synchronized now: