Blazouter ๐
July 1, 2026 ยท View on GitHub
A powerful React Router-like routing library for Blazor applications. Blazouter brings the best features of React Router to the Blazor ecosystem with dedicated packages for each hosting model.
๐ Why Blazouter?
Blazor's built-in routing is functional but lacks many modern features that developers expect from frameworks like React Router. Blazouter fills this gap by providing:
- โ Type-safe - Full IntelliSense support
- โ Lazy loading - Load components on-demand
- โ True nested routing - Not just @page directives
- โ Built-in route guards - Protect your routes easily
- โ Beautiful transitions - Smooth animations between routes
- โ Programmatic navigation - Navigate imperatively with ease
โจ Features
Blazouter addresses the limitations of traditional Blazor routing:
| Feature | React Router | Blazor Router | Blazouter |
|---|---|---|---|
| Active Links | โ Built-in NavLink | โ ๏ธ Manual active class | โ Automatic with RouterLink |
| Lazy Loading | โ Route-based code splitting | โ Still limited in WASM | โ ComponentLoader + WASM RCL assembly lazy loading |
| Route Guards | โ Easy with wrappers/hooks | โ Manual, component-based | โ Built-in IRouteGuard interface |
| Layout System | โ Component composition | โ ๏ธ Static @layout | โ Dynamic per-route with priority |
| Nested Routes | โ Easy to define child routes | โ Limited, single level with @page | โ Unlimited nesting with RouterOutlet |
| Error Handling | โ Error boundaries | โ Manual | โ Built-in IRouterErrorHandler |
| Attribute Routes | โ JSX-based | โ @page only | โ 11 attribute types with full config |
| Dynamic Params | โ Easy route parameters | โ Available but basic | โ Enhanced with RouterStateService |
| Route Transitions | โ Very easy | โ No native support | โ 14 built-in transition types |
| Route Middleware | โ Route-level middleware | โ No native support | โ Built-in IRouteMiddleware interface |
| Query String Helpers | โ URLSearchParams API | โ Manual parsing | โ Type-safe fluent API with 30+ methods |
| Conditional Rendering | โ Direct with <Route> | โ Manual via state | โ Component-based rendering |
| Programmatic Navigation | โ navigate("/path") | โ NavigationManager.NavigateTo | โ Enhanced RouterNavigationService |
Key Features
- ๐ Route Parameters: Easy access to route and query parameters
- ๐ฏ Nested Routes: Define complex hierarchical route structures easily
- โก Lazy Loading: Load components on-demand for better performance
- ๐ญ Dynamic Components: Load components dynamically based on routes
- ๐ Route Guards: Protect routes with authentication and authorization logic
- ๐ท๏ธ Attribute-Based Routing: Declarative route configuration using attributes
- ๐ Layout System: Flexible layout management with default and per-route layouts
- ๐ Programmatic Navigation: Navigate imperatively with enhanced navigation service
- ๐ง Route Middleware: Execute code before/after navigation for logging, analytics, data preloading
- โ ๏ธ Error Handling: Comprehensive error handling with custom error handlers and retry mechanisms
- ๐ง Query String Utilities: Type-safe query string builder and typed parameter parsing with fluent API
- ๐จ Route Transitions: Beautiful animations when navigating between routes with 14 built-in transition types
๐ฆ Available Packages
Blazouter provides specialized packages for each Blazor hosting model:
| Package | Description | Target Frameworks |
|---|---|---|
| Blazouter | Core routing library | net6.0, net7.0, net8.0, net9.0, net10.0 |
| Blazouter.Server | Blazor Server extensions | net8.0, net9.0, net10.0 |
| Blazouter.Hybrid | Blazor Hybrid/MAUI extensions | net10.0 (iOS, Android, macOS, Windows) |
| Blazouter.WebAssembly | Blazor WebAssembly extensions | net6.0, net7.0, net8.0, net9.0, net10.0 |
Note: The
Blazouter.Webpackage has been deprecated. For Blazor Web Applications, useBlazouter.Serverfor the server project andBlazouter.WebAssemblyfor the client project.
๐ Quick Start
Installation
Choose the package(s) based on your hosting model:
For Blazor Server:
dotnet add package Blazouter
dotnet add package Blazouter.Server
For Blazor Hybrid/MAUI:
dotnet add package Blazouter
dotnet add package Blazouter.Hybrid
For Blazor WebAssembly:
dotnet add package Blazouter
dotnet add package Blazouter.WebAssembly
For Blazor Web Application (.NET 8+):
Server project:
dotnet add package Blazouter
dotnet add package Blazouter.Server
Client project:
dotnet add package Blazouter
dotnet add package Blazouter.WebAssembly
Setup
1. Register Blazouter services
// In Program.cs (WebAssembly & Server) or MauiProgram.cs (Hybrid)
using Blazouter.Extensions;
builder.Services.AddBlazouter();
2. Platform-specific configuration
Blazor Server
Add Blazouter support to routing in Program.cs:
using Blazouter.Server.Extensions;
app.MapRazorComponents<App>()
.AddBlazouterSupport() // Required for Server mode
.AddInteractiveServerRenderMode();
Create a Routes.razor component:
@using Blazouter.Models
@using Blazouter.Components
<Router Routes="@_routes">
<NotFound>
<h1>404 - Page Not Found</h1>
</NotFound>
</Router>
@code {
private List<RouteConfig> _routes = new()
{
new RouteConfig { Path = "/", Component = typeof(Pages.Home) },
// Add more routes...
};
}
Use in App.razor:
<Routes @rendermode="InteractiveServer" />
Important: The @rendermode="InteractiveServer" attribute is required to enable SignalR connection and interactivity in Blazor Server applications (.NET 8+).
Blazor WebAssembly
Use the Router component in App.razor:
@using Blazouter.Models
@using Blazouter.Components
<Router Routes="@_routes">
<NotFound>
<h1>404 - Page Not Found</h1>
</NotFound>
</Router>
@code {
private List<RouteConfig> _routes = new()
{
new RouteConfig { Path = "/", Component = typeof(Pages.Home) },
// Add more routes...
};
}
Blazor Hybrid (MAUI)
Register in MauiProgram.cs:
using Blazouter.Hybrid.Extensions;
builder.AddBlazouterSupport(); // Instead of builder.Services.AddBlazouter()
Use the Router component in your root Blazor component:
@using Blazouter.Models
@using Blazouter.Components
<Router Routes="@_routes">
<NotFound>
<h1>404 - Page Not Found</h1>
</NotFound>
</Router>
@code {
private List<RouteConfig> _routes = new()
{
new RouteConfig { Path = "/", Component = typeof(Pages.Home) },
// Add more routes...
};
}
Blazor Web Application (.NET 8+)
Server project - Add Blazouter support in Program.cs:
using Blazouter.Server.Extensions;
app.MapRazorComponents<App>()
.AddBlazouterSupport() // Required for Blazor Server/Web
.AddInteractiveServerRenderMode()
.AddInteractiveWebAssemblyRenderMode();
Server project - Create a Routes.razor component:
@using Blazouter.Models
@using Blazouter.Components
@using ServerPages = YourApp.Server.Components.Pages
@using ClientPages = YourApp.Client.Components.Pages
<Router Routes="@_routes">
<NotFound>
<h1>404 - Page Not Found</h1>
</NotFound>
</Router>
@code {
private List<RouteConfig> _routes = new()
{
// Server-side pages
new RouteConfig { Path = "/", Component = typeof(ServerPages.Home) },
// Client-side pages
new RouteConfig { Path = "/about", Component = typeof(ClientPages.About) },
// Add more routes...
};
}
Server project - Use in App.razor with InteractiveServer render mode:
<!-- Use InteractiveServer to keep Routes on server -->
<Routes @rendermode="InteractiveServer" />
<!-- Or use InteractiveWebAssembly for client-only -->
<Routes @rendermode="InteractiveWebAssembly" />
InteractiveAuto provides the best experience by starting with fast server rendering, then automatically switching to WebAssembly once it's downloaded.
3. Include the CSS
<link rel="stylesheet" href="_content/Blazouter/blazouter[.min].css" />
4. Define your routes with optional layout
// Using a default layout for all routes
<Router Routes="@_routes" DefaultLayout="typeof(MainLayout)">
<NotFound><h1>404</h1></NotFound>
</Router>
@code {
private List<RouteConfig> _routes = new()
{
new RouteConfig
{
Path = "/",
Component = typeof(Pages.Home),
Transition = RouteTransition.Fade
},
new RouteConfig
{
Path = "/users",
Component = typeof(Pages.UserLayout),
Children = new List<RouteConfig>
{
new RouteConfig { Path = ":id", Component = typeof(Pages.UserDetail) }
}
},
new RouteConfig
{
Path = "/admin",
Component = typeof(Pages.Admin),
Layout = typeof(AdminLayout) // Override default layout
},
new RouteConfig
{
Path = "/print",
Component = typeof(Pages.Print),
Layout = null // No layout for this route
}
};
}
๐ Usage Examples
Attribute-Based Routing
Define routes declaratively using attributes directly on your components:
using Blazouter.Enums;
using Blazouter.Models;
using Blazouter.Attributes;
using Microsoft.AspNetCore.Components;
[Route("/admin")]
[RouteTitle("Admin Panel")]
[RouteGuard(typeof(AuthGuard))]
[RouteTransition(RouteTransition.Fade)]
public class AdminPage : ComponentBase
{
// Component implementation
}
Enable attribute-based routes in your app:
// In App.razor.cs or Routes.razor.cs
private List<RouteConfig> _routes = new List<RouteConfig>()
.AddAttributeRoutes(typeof(App).Assembly);
// Or mix with programmatic routes
private List<RouteConfig> _routes = new List<RouteConfig>
{
new RouteConfig { Path = "/", Component = typeof(Home) }
}.AddAttributeRoutes(typeof(App).Assembly);
๐ Learn more about Attribute-Based Routing โ
Layouts
Blazouter provides flexible layout management with DefaultLayout and per-route Layout properties.
// Set a default layout for all routes
<Router Routes="@_routes" DefaultLayout="typeof(MainLayout)">
<NotFound><h1>404</h1></NotFound>
</Router>
@code {
private List<RouteConfig> _routes = new()
{
// Uses default layout (MainLayout)
new RouteConfig { Path = "/", Component = typeof(Home) },
// Override with different layout
new RouteConfig
{
Path = "/admin",
Component = typeof(AdminDashboard),
Layout = typeof(AdminLayout) // Uses AdminLayout instead
},
// No layout for this route
new RouteConfig
{
Path = "/print",
Component = typeof(PrintView),
Layout = null // Renders without any layout
}
};
}
Layout Priority: RouteConfig.Layout > Router.DefaultLayout > No Layout
Your layout component must inherit from LayoutComponentBase and use @Body:
@inherits LayoutComponentBase
<div class="app-layout">
<nav><!-- Navigation --></nav>
<main>
@Body <!-- Page component renders here -->
</main>
<footer><!-- Footer --></footer>
</div>
Basic Routing
new RouteConfig
{
Path = "/about",
Component = typeof(About),
Title = "About Us",
Transition = RouteTransition.Slide
}
Nested Routes
new RouteConfig
{
Path = "/products",
Component = typeof(ProductLayout),
Children = new List<RouteConfig>
{
new RouteConfig
{
Path = "",
Component = typeof(ProductList),
Exact = true
},
new RouteConfig
{
Path = ":id",
Component = typeof(ProductDetail)
}
}
}
Use <RouterOutlet /> in the parent component to render child routes:
@using Blazouter.Components
<div class="layout">
<h1>Products</h1>
<RouterOutlet />
</div>
Route Middleware
Execute code before and after route navigation for logging, analytics, data preloading, and more:
new RouteConfig
{
Path = "/admin",
Component = typeof(AdminPanel),
Middleware = new List<Type>
{
typeof(LoggingMiddleware),
typeof(TimingMiddleware),
typeof(AnalyticsMiddleware)
}
}
Create a middleware:
using Blazouter.Models;
using Blazouter.Interfaces;
public class LoggingMiddleware : IRouteMiddleware
{
public async Task InvokeAsync(RouteMiddlewareContext context, Func<Task> next)
{
// Before navigation
Console.WriteLine($"Navigating to: {context.Path}");
// Continue to next middleware or component
await next();
// After navigation
Console.WriteLine($"Navigation completed");
}
}
Middleware can share data with components:
public class DataPreloadMiddleware : IRouteMiddleware
{
public async Task InvokeAsync(RouteMiddlewareContext context, Func<Task> next)
{
// Store data - will only be passed if component has matching parameter
context.Data["PreloadedData"] = await LoadDataAsync();
context.Data["LoadTimestamp"] = DateTime.UtcNow;
await next();
}
}
// In your component - only define parameters you need
[Parameter]
public object? PreloadedData { get; set; }
// LoadTimestamp is automatically filtered out if not defined
Note: The Router automatically filters both middleware data and route data to only pass parameters that the component actually has. You can store any data in context.Data or use RouteData attributes without worrying about parameter mismatch errors.
Route Guards (Protected Routes)
Control access to routes based on authentication or authorization:
new RouteConfig
{
Path = "/admin",
Component = typeof(AdminPanel),
Guards = new List<Type> { typeof(AuthGuard) }
}
Create a guard:
using Blazouter.Models;
using Blazouter.Interfaces;
public class AuthGuard : IRouteGuard
{
public async Task<bool> CanActivateAsync(RouteMatch match)
{
// Check authentication
return await IsAuthenticated();
}
public Task<string?> GetRedirectPathAsync(RouteMatch match)
{
return Task.FromResult<string?>("/login");
}
}
Lazy Loading
ComponentLoader - Load components on-demand:
new RouteConfig
{
Path = "/reports",
ComponentLoader = async () =>
{
// Simulate loading delay or dynamic import
await Task.Delay(100);
return typeof(ReportsPage);
}
}
WASM RCL Assembly Lazy Loading - Load entire Razor Class Library assemblies on demand in Blazor WebAssembly:
@using System.Reflection
@using Blazouter.Models
@using Blazouter.Components
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@inject LazyAssemblyLoader AssemblyLoader
<Router Routes="@_routes"
DefaultLayout="typeof(MainLayout)"
OnNavigateAsync="@OnNavigateAsync"
AdditionalAssemblies="@_lazyLoadedAssemblies">
<Loading>
<p>Loading...</p>
</Loading>
<NotFound>
<h1>404 - Page Not Found</h1>
</NotFound>
</Router>
@code {
private readonly List<Assembly> _lazyLoadedAssemblies = [];
private async Task OnNavigateAsync(BlazouterNavigationContext context)
{
if (context.Path.StartsWith("/module-page", StringComparison.OrdinalIgnoreCase))
{
if (_lazyLoadedAssemblies.Count == 0)
{
var assemblies = await AssemblyLoader.LoadAssembliesAsync(
["MyModule.wasm"]);
_lazyLoadedAssemblies.AddRange(assemblies);
}
}
}
}
Configure lazy-loaded assemblies in your project file:
<ItemGroup>
<BlazorWebAssemblyLazyLoad Include="MyModule.wasm" />
</ItemGroup>
Route Links
@using Blazouter.Components
<nav>
<RouterLink Href="/" Exact="true" ActiveClass="active">Home</RouterLink>
<RouterLink Href="/about" ActiveClass="active">About</RouterLink>
<RouterLink Href="/users" ActiveClass="active">Users</RouterLink>
</nav>
Programmatic Navigation
@inject RouterNavigationService NavService
<button @onclick="NavigateToUser">Go to User</button>
@code {
private void NavigateToUser()
{
NavService.NavigateTo("/users/123");
}
}
Access Route Parameters
@using Blazouter.Services
@inject RouterStateService RouterState
<h1>User: @_userId</h1>
@code {
private string? _userId;
protected override void OnInitialized()
{
_userId = RouterState.GetParam("id");
}
}
Query String Utilities
Blazouter provides comprehensive query string helpers for type-safe parameter handling:
Type-safe query parameter parsing:
@using Blazouter.Extensions
@inject RouterStateService RouterState
@code {
protected override void OnInitialized()
{
// Typed parsing with defaults
int page = RouterState.GetQueryInt("page", 1);
bool active = RouterState.GetQueryBool("active", false);
DateTime? date = RouterState.GetQueryDateTimeOrNull("date");
// Get all query parameters
var allParams = RouterState.GetAllQueryParams();
}
}
Fluent query string building:
@using Blazouter.Utilities
@inject RouterNavigationService NavService
@code {
private void NavigateWithQuery()
{
// Build query strings with type safety
NavService.NavigateToWithQuery("/search", q => q
.Add("term", "blazor")
.Add("active", true)
.Add("page", 2));
}
}
Update query parameters:
// Replace specific parameters while keeping others
NavService.NavigateToWithUpdatedQuery(RouterState, null, q => q
.Set("page", currentPage + 1)
.Set("sort", "name"));
// Remove parameters
NavService.NavigateToWithRemovedQuery(RouterState, "filter", "sort");
// Clear all parameters
NavService.NavigateToWithClearedQuery(RouterState);
The QueryStringBuilder supports 15 type overloads including: string, int, long, decimal, double, bool, DateTime, Guid, enum, and their nullable variants.
๐จ Route Transitions
Blazouter includes 14 built-in transitions for beautiful page navigation:
Fade- Fade in animationScale- Scale in animationFlip- 3D card flip animationSlide- Slide from left animationPop- Bounce effect with elastic easingSlideUp- Slide from bottom animationNone- No transition animation (instant)Rotate- Spinning entrance along Z-axisReveal- Mask opening from bottom to topSlideFade- Combined slide and fade effectBlur- Focus transition from blurred to sharpSwipe- Mobile-style swipe reveal from right to leftCurtain- Theatrical curtain opening from top to bottomSpotlight- Dramatic lighting effect with brightness and blurLift- Content lifts up with subtle scaling and shadow (iOS-style)
new RouteConfig
{
Path = "/",
Component = typeof(Home),
Transition = RouteTransition.Fade
}
โ ๏ธ Error Handling
Blazouter provides comprehensive error handling capabilities to gracefully manage routing errors:
Built-in Error Handling
Use the ErrorContent parameter in the Router component to display custom error pages:
<Router Routes="@_routes">
<ErrorContent Context="errorInfo">
<div class="error-page">
<h1>โ ๏ธ Routing Error</h1>
<p><strong>@errorInfo.ErrorType</strong></p>
<p>@errorInfo.Message</p>
@if (errorInfo.Retry != null)
{
<button @onclick="@errorInfo.Retry">Try Again</button>
}
</div>
</ErrorContent>
<NotFound>
<h1>404 - Page Not Found</h1>
</NotFound>
</Router>
Custom Error Handlers
Implement IRouterErrorHandler for custom error handling logic:
public class CustomRouterErrorHandler : IRouterErrorHandler
{
public Task HandleErrorAsync(RouterErrorContext context)
{
// Log error, send telemetry, etc.
Console.WriteLine($"Route error: {context.ErrorType} - {context.Message}");
return Task.CompletedTask;
}
}
// Register in Program.cs
builder.Services.AddBlazouterErrorHandler<CustomRouterErrorHandler>();
Error Types
InvalidRoute- Invalid route configurationGuardRejected- Route guard denied accessNavigationFailed- Navigation operation failedComponentLoadFailed- Component failed to load
๐ Advanced Caching Strategies
Blazouter includes sophisticated caching mechanisms to optimize route matching and component loading performance. The caching layer is transparent, requiring no code changes while significantly improving navigation speed, especially for applications with complex routing structures.
Features
- Route Match Caching: Cached route matching results for faster subsequent navigations
- Component Type Caching: Lazily loaded components are cached to avoid repeated async loading
- LRU Eviction: Least Recently Used (LRU) policy ensures efficient memory usage
- TTL Support: Optional time-to-live for cache entries
- Thread-Safe: Concurrent-safe implementation for server-side scenarios
- Statistics Tracking: Monitor cache performance with detailed metrics
Default Configuration
Caching is enabled by default with sensible defaults:
// In Program.cs - caching is automatic
builder.Services.AddBlazouter();
Default settings:
- Route match cache: Enabled (max 100 entries)
- Component type cache: Enabled (max 50 entries)
- TTL: No expiration (cached indefinitely)
- Statistics: Disabled (minimal overhead)
Custom Cache Configuration
Fine-tune caching behavior for your application's needs:
// In Program.cs
builder.Services.AddBlazouter(options =>
{
// Adjust cache sizes
options.MaxRouteMatchCacheSize = 200; // Increase for apps with many routes
options.MaxComponentTypeCacheSize = 100; // More lazy-loaded components
// Enable statistics tracking
options.EnableStatistics = true; // Monitor cache effectiveness
// Set TTL for development scenarios
options.RouteMatchCacheTTLSeconds = 300; // 5 minutes (0 = no expiration)
// Disable specific caches if needed
options.EnableRouteMatchCache = true; // Route matching cache
options.EnableComponentTypeCache = true; // Component loading cache
});
Per-Route Cache Control
Control caching at the individual route level for fine-grained optimization:
new RouteConfig
{
Path = "/admin/dashboard",
Component = typeof(AdminDashboard),
EnableCache = false // Never cache this route
}
new RouteConfig
{
Path = "/static-content",
Component = typeof(StaticPage),
EnableCache = true // Always cache (even if global caching disabled)
}
new RouteConfig
{
Path = "/default-page",
Component = typeof(DefaultPage),
EnableCache = null // Use global cache settings (default)
}
Use cases for disabling cache per route:
- Admin dashboards with real-time data
- User-specific pages that change frequently
- Routes with middleware that should run every time
- Error pages for testing
- Routes with dynamic content
Cache Statistics
Monitor cache performance to optimize configuration:
@inject IRouteCacheService CacheService
@code {
private void ShowCacheStats()
{
var stats = CacheService.GetStatistics();
Console.WriteLine($"Total Requests: {stats.TotalRequests}");
Console.WriteLine($"Cache Hits: {stats.CacheHits}");
Console.WriteLine($"Cache Misses: {stats.CacheMisses}");
Console.WriteLine($"Hit Rate: {stats.HitRate:F2}%");
Console.WriteLine($"Route Cache Size: {stats.RouteMatchCacheSize}");
Console.WriteLine($"Component Cache Size: {stats.ComponentTypeCacheSize}");
}
}
Note: Statistics tracking must be enabled in cache options to collect metrics.
Cache Management
Programmatically manage cache entries when needed:
@inject IRouteCacheService CacheService
@code {
// Clear all cached entries
private void ClearCache()
{
CacheService.Clear();
}
// Invalidate specific route
private void InvalidateRoute(string path)
{
CacheService.InvalidateRouteMatch(path);
}
}
Performance Benefits
The caching layer provides significant performance improvements:
- First Navigation: Normal route matching (no cache)
- Subsequent Navigations: Instant lookup from cache (10-50x faster)
- Lazy Loading: Components loaded once, cached for instant reuse
- Memory Efficient: LRU eviction keeps memory usage bounded
When to Adjust Cache Settings
Increase cache sizes if you have:
- Many unique routes in your application
- Frequent navigation between many different pages
- High memory availability
Enable TTL if you have:
- Dynamic routes that change during runtime
- Development environment with hot reload
- Routes that depend on external configuration
Disable caching if you need:
- Real-time route configuration updates
- Debugging route matching logic
- Minimal memory footprint
๐ Complete Caching Documentation โ
๐ง TypeScript Integration
Blazouter includes TypeScript-based JavaScript interop for enhanced browser integration with full type safety.
Features
- SEO Support: Set meta tags, Open Graph tags, and canonical URLs
- Type Safety: Full TypeScript definitions with
.d.tsfiles for IntelliSense - Browser Navigation: True browser back/forward navigation using the History API
- Document Manipulation: Dynamic title updates, meta tags, scrolling, and focus management
Installation
Enable JavaScript interop by registering the services:
builder.Services.AddBlazouter();
builder.Services.AddBlazouterInterop(); // Enable TypeScript interop
Add the JavaScript module import to your index.html:
<!-- In wwwroot/index.html, add this in the <head> section -->
<script type="module" src="_content/Blazouter/js/index.js"></script>
Browser Navigation Example
@inject RouterNavigationService NavService
<button @onclick="GoBack">โ Back</button>
<button @onclick="GoForward">Forward โ</button>
@code {
private async Task GoBack()
{
await NavService.GoBackAsync(); // Uses browser History API
}
private async Task GoForward()
{
await NavService.GoForwardAsync();
}
}
Document Manipulation Example
@inject DocumentInterop DocumentInterop
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// Update page title
await DocumentInterop.SetTitleAsync("Home - My App");
// Set meta tags for SEO
await DocumentInterop.SetMetaTagAsync("description", "Welcome to my app");
// Set Open Graph tags for social sharing
await DocumentInterop.SetOpenGraphTagAsync("og:title", "My App");
// Scroll to top on navigation
await DocumentInterop.ScrollToTopAsync();
}
}
}
๐ Full TypeScript Integration Documentation โ
๐๏ธ Project Structure
Blazouter/
โโโ src/
โ โโโ Blazouter/ # Core library (required)
โ โ โโโ Attributes/ # Route attribute definitions
โ โ โโโ Components/ # Router components (Router, RouterLink, RouterOutlet)
โ โ โ โโโ Layouts/ # Built-in layout components
โ โ โโโ Enums/ # Enumeration types (RouteTransition, RouterErrorType)
โ โ โโโ Extensions/ # Service collection and router extensions (typed query parameters, navigation, transitions)
โ โ โโโ Guards/ # Route guard implementations (AuthGuard)
โ โ โโโ Handlers/ # Error handler implementations (DefaultRouterErrorHandler)
โ โ โโโ Interfaces/ # Interface definitions (IRouteGuard, IRouteMiddleware, IRouteMatcherService, IRouterErrorHandler)
โ โ โโโ Interops/ # JavaScript interop services (NavigationInterop, DocumentInterop, StorageInterop, ViewportInterop, ClipboardInterop)
โ โ โโโ Models/ # Route models (RouteConfig, RouteMatch, RouterErrorContext, etc.)
โ โ โโโ Resources/ # Embedded resources
โ โ โโโ Services/ # Routing services (RouterStateService, RouteMatcherService, RouterNavigationService)
โ โ โโโ Utilities/ # Query string builder and helper utilities
โ โ โโโ wwwroot/ # CSS and assets (blazouter.css, blazouter.min.css)
โ โ โโโ js/ # Compiled JavaScript modules with TypeScript definitions (.js, .d.ts, .js.map)
โ โโโ Blazouter.TypeScript/ # TypeScript source files for JavaScript interop
โ โ โโโ TypeScript/ # TypeScript source files (navigation.ts, document.ts, storage.ts, viewport.ts, clipboard.ts, index.ts)
โ โ โโโ package.json # NPM dependencies for TypeScript compilation
โ โ โโโ tsconfig.json # TypeScript compiler configuration
โ โโโ Blazouter.Server/ # Server-specific extensions
โ โ โโโ Extensions/ # Server integration (AddBlazouterSupport)
โ โ โโโ Pages/ # Server pages
โ โ โโโ Resources/ # Embedded resources
โ โโโ Blazouter.WebAssembly/ # WebAssembly-specific extensions
โ โ โโโ Resources/ # Embedded resources
โ โโโ Blazouter.Web/ # Web-specific extensions (DEPRECATED - use Server + WebAssembly)
โ โ โโโ Extensions/ # Web integration
โ โ โโโ Pages/ # Web pages
โ โ โโโ Resources/ # Embedded resources
โ โโโ Blazouter.Hybrid/ # Hybrid/MAUI-specific extensions
โ โโโ Extensions/ # MAUI integration (AddBlazouterSupport)
โ โโโ Resources/ # Embedded resources
โโโ samples/
โโโ Blazouter.Server.Sample/ # Server sample app
โโโ Blazouter.WebAssembly.Sample/ # WebAssembly sample app
โโโ Blazouter.Hybrid.Sample/ # Hybrid/MAUI sample app
โโโ Blazouter.Web.Sample/ # Web (Server + WASM) sample app
โโโ Blazouter.Web.Sample/ # Server project
โโโ Blazouter.Web.Client.Sample/ # Client project
๐ฎ Running the Samples
Blazouter includes multiple sample applications for different hosting models:
Blazor Server Sample:
cd samples/Blazouter.Server.Sample
dotnet run
Blazor WebAssembly Sample:
cd samples/Blazouter.WebAssembly.Sample
dotnet run
Blazor Hybrid Sample (MAUI):
cd samples/Blazouter.Hybrid.Sample
dotnet build -t:Run -f net10.0-windows10.0.19041.0
Blazor Web Sample (.NET 8+ with Server + WASM):
cd samples/Blazouter.Web.Sample/Blazouter.Web.Sample
dotnet run
Then navigate to the URL shown in your terminal (typically https://localhost:5001 or http://localhost:5000).
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
๐ License
This project is licensed under the MIT License.
๐ Project Stats
- Supported .NET versions: .NET 6.0, 7.0, 8.0, 9.0, 10.0
- Platforms: Blazor WebAssembly, Blazor Server, Blazor Hybrid (MAUI)
- License: MIT
- Packages:
๐ Links
- Changelog
- Issue Tracker
- Documentation
- Caching System
- Contributing Guide
- Sample Applications
- TypeScript Integration
๐ Acknowledgments
Inspired by React Router and built to bring similar capabilities to the Blazor ecosystem.
๐ Roadmap
- Route middleware support
- Performance optimizations
- Advanced caching strategies
- Query string helpers and utilities
- Better TypeScript integration for JS interop
- WASM RCL assembly lazy loading (OnNavigateAsync + AdditionalAssemblies)
โญ Show Your Support
If you find Blazouter helpful, please consider giving it a star on GitHub! It helps the project grow and reach more developers.
Made with โค๏ธ for the Blazor community