Blazor.NavigationStack 1.0.6

dotnet add package Blazor.NavigationStack --version 1.0.6
                    
NuGet\Install-Package Blazor.NavigationStack -Version 1.0.6
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Blazor.NavigationStack" Version="1.0.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Blazor.NavigationStack" Version="1.0.6" />
                    
Directory.Packages.props
<PackageReference Include="Blazor.NavigationStack" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Blazor.NavigationStack --version 1.0.6
                    
#r "nuget: Blazor.NavigationStack, 1.0.6"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=Blazor.NavigationStack&version=1.0.6
                    
Install Blazor.NavigationStack as a Cake Addin
#tool nuget:?package=Blazor.NavigationStack&version=1.0.6
                    
Install Blazor.NavigationStack as a Cake Tool

Blazor Navigation Stack

NuGet (with prereleases)

A flexible navigation stack for Blazor. Manage complex navigation while retaining states, ideal for wizards, multi-step forms, and nested workflows.

If you find this project helpful, please consider giving it a star! ⭐

Table of Contents

Samples/Demo

<a href="https://purple-rock-0e47e3410.6.azurestaticapps.net/" target="_blank">Live Demo</a> <table> <tr> <td align="center"><strong>Multi-step forms</strong></td> <td align="center"><strong>Visual customization</strong></td> </tr> <tr> <td><img src="ReadmeAssets/SimpleUsage.gif" alt="Demonstration of nested workflow navigation."></td> <td><img src="ReadmeAssets/Customized.gif" alt="Demonstration of a visually customized navigation stack."></td> </tr> <tr> <td align="center"><strong>Wizards</strong></td> <td align="center"><strong>Preserving states</strong></td> </tr> <tr> <td><img src="ReadmeAssets/Steps.gif" alt="Demonstration of a multi-step wizard."></td> <td><img src="ReadmeAssets/PreserveStates.gif" alt="Demonstration of state preservation across navigation."></td> </tr> </table>

Installation

Add the nuget package in your Blazor project

> dotnet add package Blazor.NavigationStack

OR

PM> Install-Package Blazor.NavigationStack

Nuget package page can be found here.

Basic Usage

Obtaining INavigationStack

All operations on the Blazor navigation stack can be done through INavigationStack interface. INavigationStack interface can be obtained through many ways.

  1. Through context

     <NavigationStack>  
      <BaseContent>  
      <button @onclick="()=>StartClicked(context)">Start</button>  
      </BaseContent>  
     </NavigationStack>  
    
     @code {  
       private void StartClicked(INavigationStack stack) {  
             //push pages to the navigation stack  
       }  
     }
    
  2. Through cascading parameter

    ComponentWithNavigationStack.razor

     <NavigationStack>  
      <BaseContent>  
      <StackPageComponent/>  
      </BaseContent>  
     </NavigationStack>
    

    StackPageComponent.razor

     @code {  
       [CascadingParameter]  
         public INavigationStack? NavigationStack { get; set; }  
     }
    
  3. Through @ref

     <NavigationStack @ref="_stack">  
     </NavigationStack>  
    
     @code {  
       private INavigationStack? _stack;  
     }
    

Add a page to the stack

  • Adding a page on top of the current one by calling INavigationStack.Push method.
  • Remove the top most page by calling INavigationStack.Pop method
void ReturnClicked() {  
    _stack.Pop();  
}  
RenderFragment Content() {  
    return @<div>  
  Content of the page  
  <button @onclick="ReturnClicked">Return</button>  
 </div>;  
}  
await _stack.Push(new StackPage() {  
    Content = Content(),  
});

Add a page expecting a result

  • Adding a page on top of the current one by calling INavigationStack.Push<T> method.
  • Setting a result and pop the cuurent page by calling INavigationStack.SetResult method.

ComponentWithStack.razor

RenderFragment Content() {  
    return @<StackPageComponent/>;  
}  
NavigationStack.Result<string> result = await _stack.Push<string>(new StackPage() {  
    Content = Content(),  
});  
if(result.IsCanceled) return;  
string? valueFromStackPage = result.Value;

StackPageComponent.razor

<div>  
 <input type="text" @bind="_value"/>  
 <button @onclick="OkClicked">Ok</button>  
</div>  
  
@code {  
  [CascadingParameter]  
    public INavigationStack? NavigationStack { get; set; }  
    private string _value = "";  
    private void OkClicked() {  
        NavigationStack?.SetResult(_value);  
    }  
}

Preserving states

State of components can be preserved in the stack frame itself.

    private class Data {
        public required string Value1 { get; init; }
        public required string Value2 { get; init; }
    }

    private Data? _data;

    private async Task ShowTableBuilder(INavigationStack stack) {
        string? value1 = null;
        string? value2 = null;

        async Task SelectValue1() {
            value1 = await ShowSelectValue(stack);
        }
        async Task SelectValue2() {
            value2 = await ShowSelectValue(stack);
        }

        void OkClicked() {
            if (value1 == null || value2 == null) return;
            stack.SetResult(new Data() {
                Value1 = value1,
                Value2 = value2,
            });
        }

        RenderFragment Content() {
            return @<div>
                <p>Select two values by navigating to sub-pages.
                   The selected values will be preserved in the stack frame allow 
                   each value to be selected separately.</p>
                <table>
                    <tr>
                        <th colspan="3">Select values</th>
                    </tr>
                    <tr>
                        <td><strong>Value1</strong></td>
                        <td>@value1</td>
                        <td>
                            <button @onclick="SelectValue1">Select value</button>
                        </td>
                    </tr>
                    <tr>
                        <td><strong>Value2</strong></td>
                        <td>@value2</td>
                        <td>
                            <button @onclick="SelectValue2">Select value</button>
                        </td>
                    </tr>
                    <tr>
                        <td colspan="3">
                            <button disabled="@(value1 == null || value2 == null)" @onclick="OkClicked">Ok</button>
                        </td>
                    </tr>
                </table>
            </div>;
        }

        NavigationStack.Result<Data> result = await stack.Push<Data>(new StackPage() {
            Content = Content(),
            Name = "Table Builder"
        });
        _data = result.Value;

    }


    private async Task<string?> ShowSelectValue(INavigationStack stack) {
        string? result = null;

        void OkClicked() {
            stack.Pop();
        }

        RenderFragment Content() {
            return @<div>
                <p>Enter a value in the input field and click 'Ok' to return to the 'Table Builder'.</p>
                <input type="text" @bind="result"/>
                <button @onclick="OkClicked">Ok</button>
            </div>;
        }

        bool success = await stack.Push(new StackPage() {
            Content = Content(),
            Name = "Select Value",
        });
        if (!success) return null;

        return result;
    }

Interacting with a page on top of the stack

  • Properties of the StackPage can be updated after it was push onto the stack by calling INavigationStack.SetName and INavigationStack.SetMenu methods.
  • Changes to the content of the current page can be updated by calling INavigationStack.Refresh. It will rerender the page similar to calling StateHasChanged on a component.
// Change the name of the current page
NavigationStack?.SetName("Page Title");

// Set a custom menu to the curret page
NavigationStack?.SetMenu(CustomMenuFragment);

// Rerender the navigation stack including the current page
NavigationStack?.Refresh();

Customization

You can customize virtually every part of the Navigation Stack, including:

  • Overall layout
  • Header stack appearance
  • Individual header styling
  • Header separators
  • Menu appearance
  • Back button

To customize the Navigation Stack, pass custom RenderFragments to the appropriate parameters of the NavigationStack component:

<NavigationStack 
    BaseName="Home"
    Layout="@CustomLayout"
    HeaderStack="@CustomHeaderStack"
    Header="@CustomHeader"
    HeaderSeparator="@CustomHeaderSeparator"
    Back="@CustomBack">
    <BaseContent>
        
    </BaseContent>
</NavigationStack>

Overall Layout

The layout controls the overall structure of the navigation stack:

private RenderFragment<NavigationStack.LayoutContext> CustomLayout => context => {
    return @<div class="dark-layout">
                <div class="dark-header">
                    <div class="header-left">
                        @context.BackButton
                        @context.HeaderStack
                    </div>
                    <div class="header-right">
                        @context.MenuStack
                    </div>
                </div>
                <div class="dark-content">
                    @context.Content
                </div>
            </div>;
};

The LayoutContext provides:

  • BackButton: Back navigation button
  • HeaderStack: Breadcrumbs/header navigation
  • MenuStack: Menu for the current page
  • Content: The main content area

Customize how navigation headers appear:

private RenderFragment<NavigationStack.HeaderContext> CustomHeader => context => {
    return @<div class="@(context.IsActive ? "header-active" : "header-inactive")">
        @context.Name
    </div>;
};

The HeaderContext provides:

  • Name: Title of the page
  • IsActive: Whether this is the currently active page

Header Stack

Change how the entire breadcrumb/header navigation appears:

private RenderFragment<NavigationStack.HeaderStackContext> CustomHeaderStack => context => {
    return @<div class="header-stack">
               @{
                   RenderFragment header = context.Headers.First();
                   <div class="header-item">
                       @header
                   </div>
               }
           </div>;
};

The HeaderStackContext provides:

  • Headers: Collection of header fragments to display

Header Separator

Customize the separator between headers:

private RenderFragment CustomHeaderSeparator => @<div class="separator-arrow">
    <span>→</span>
</div>;

The MenuContext provides:

  • Options: Collection of menu item fragments to display

Back Button

Change the appearance and behavior of the back button:

private RenderFragment<NavigationStack.BackContext> CustomBack => context => {
    return @<button class="back-button" @onclick="context.Back">
        <span>◀</span> Back
    </button>;
};

The BackContext provides:

  • Back: Action to perform INavigationStack.Cancel

For a complete example, see the Blazor.NavigationStack.TestApp/Components/Pages/Customize.razor component which demonstrates a dark-themed custom navigation stack.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.6 177 5/16/2025
1.0.5 210 5/16/2025
1.0.4 213 5/15/2025
1.0.3 208 5/15/2025
1.0.2 211 5/15/2025
1.0.1 219 5/14/2025
1.0.0 220 5/14/2025