Sometimes you want to have a custom 404 page - and since .NET 8 and "Blazor WebApps" the <NotFound> tag of the Router doesn't work anymore, so let's create a custom page for that.
Before Blazor Web App (aka Blazor Server and Client)
In "earlier" times you could do the following inside your Router component:
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Here your custom component or code that is shown when the navigation results in a 404</p>
</LayoutView>
</NotFound>
</Router>
That still works in the "old" approach where you either the client-side or server-side approach (aka something like <script src="_framework/blazor.server.js"></script>). But in the new Web App model that doesn't work. Still, you are able to pass in a NotFound child to the Router but it doesn't get picked up. The underlying Router type is different in the Web App (where you have <script src="_framework/blazor.web.js"></script> somewhere in your App.razor and have AddInteractiveServerComponents in your sevice container).
Adding a "fall trough" page
But we can easily define a web-page that is displayed with a lower specificity so that it has the least priority. Let's call that NotFoundPage.razor:
@page "/{*route:nonfile}"
<p>Here your custom component or code that is shown when the navigation results in a 404</p>
@code {
[Parameter]
public string? Route { get; set; }
}
The Route isn't used but mandatory - otherwise Blazor will throw an exception that it can not set route to a property. On my companies website https://bitspire.ch we did exactly that. Head over to: https://bitspire.ch/not-found (or add any useless subpage that probably doesn't exist) and you are greeted with a custom 404 page.