Del 4 av 8

Routing & layout

Hur Blazor matchar URL:er till komponenter, hur rutter tar parametrar, och hur du strukturerar app-skalet med layouter och NavMenu.

Lektion 4 — V4. Vi binder ihop appens sidor till en helhet med routing, navigation och layouter — det som gör appen till mer än en samling lösa komponenter.

@page-direktivet

En komponent blir en sida genom att deklarera en eller flera @page-rutter högst upp:

@page "/"
@page "/home"

<h1>Välkommen!</h1>

Routern (definierad i Routes.razor) skannar projektet efter alla komponenter med @page och bygger upp tabellen automatiskt.

Ruttparametrar

@page "/products/{Id:int}"

<h1>Produkt @Id</h1>

@code {
    [Parameter] public int Id { get; set; }
}
ConstraintMatchar
{Id:int}Heltal
{Slug}Sträng (default) — se förklaring nedan
{Date:datetime}DateTime
{Active:bool}true/false
{Id:guid}Guid
{*Path}Catch-all (allt återstående)
Vad är en slug?

En slug är en URL-vänlig version av en text — vanligtvis en titel. Ordet kommer från tidningsbranschen där en "slug" var ett kortnamn för en artikel.

I webbutveckling innebär det att du tar en läsbar text, gör om den till gemener, ersätter mellanslag med bindestreck och tar bort specialtecken:

OriginalSlug
Introduktion till Blazorintroduktion-till-blazor
Vad är en Route Parameter?vad-ar-en-route-parameter
Tips & Tricks 2026tips-tricks-2026

Slugs används i stället för siffror när URL:en ska vara läsbar och SEO-vänlig:

I Blazor är en slug-parameter bara en vanlig string-parameter utan constraint — därav "(default)" i tabellen. Du genererar och lagrar slugen själv i din modell.

@page "/blogg/{Slug}"

<h1>@artikel?.Titel</h1>
<p>@artikel?.Innehall</p>

@code {
    [Parameter] public string Slug { get; set; } = "";

    private Artikel? artikel;

    protected override void OnParametersSet()
    {
        // Hitta artikeln vars slug matchar URL-segmentet
        artikel = artikelService.HittaSlug(Slug);
        if (artikel is null) Nav.NotFound();
    }
}

Frågesträngar (query strings)

@page "/search"

<p>Söker efter: @Query (sida @Page)</p>

@code {
    [Parameter, SupplyParameterFromQuery] public string? Query { get; set; }
    [Parameter, SupplyParameterFromQuery(Name = "p")] public int Page { get; set; } = 1;
}

URL: /search?Query=blazor&p=2 ger Query="blazor", Page=2.

NavigationManager — navigering i kod

@inject NavigationManager Nav

<button @onclick="GoToProduct">Gå till produkt 42</button>

@code {
    private void GoToProduct()
        => Nav.NavigateTo("/products/42");

    protected override void OnInitialized()
    {
        // Lyssna på navigationsändringar
        Nav.LocationChanged += (sender, args) =>
        {
            Console.WriteLine($"Navigerade till {args.Location}");
        };
    }
}
Bra metoder på NavigationManager

NavLink — länkar med automatisk active-klass

<NavLink href="/" Match="NavLinkMatch.All">Start</NavLink>
<NavLink href="/products">Produkter</NavLink>
<NavLink href="/about">Om</NavLink>

NavLink får CSS-klassen active när dess href matchar nuvarande URL. Match="NavLinkMatch.All" kräver exakt match (annars matchas alla som börjar med href).

Layouter

En layout är en speciell komponent som ärver från LayoutComponentBase och innehåller @Body där sidans innehåll ska renderas.

@* Components/Layout/MainLayout.razor *@
@inherits LayoutComponentBase

<div class="app">
    <header>
        <h1>Min Blazor-app</h1>
        <NavMenu />
    </header>

    <main>
        @Body
    </main>

    <footer>© 2026 YH-kursen</footer>
</div>

Använda olika layout per sida

@page "/print/{Id:int}"
@layout PrintLayout

<h1>Utskrift av order @Id</h1>

Du kan också sätta default-layout för en mapp via en _Imports.razor-fil:

@* Components/Pages/Admin/_Imports.razor *@
@layout AdminLayout

NavMenu — egen sidobar

@* Components/Layout/NavMenu.razor *@
<nav class="sidebar">
    <NavLink href="/" Match="NavLinkMatch.All">🏠 Start</NavLink>
    <NavLink href="/products">📦 Produkter</NavLink>
    <NavLink href="/orders">🧾 Ordrar</NavLink>
    <NavLink href="/admin">⚙️ Admin</NavLink>
</nav>

Hantera 404

I .NET 10 är 404-hanteringen helt omgjord. Det gamla <NotFound>-render fragmentet i Router är borttaget och fungerar inte längre. I stället pekar du Router på en hel komponent via NotFoundPage:

@* Routes.razor *@
<Router AppAssembly="@typeof(Program).Assembly"
        NotFoundPage="typeof(Pages.NotFound)">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
</Router>
@* Components/Pages/NotFound.razor *@
@page "/not-found"

<PageTitle>404</PageTitle>
<h1>404 — Sidan hittades inte</h1>
<p>Den begärda adressen finns inte.</p>

Och du kan trigga 404 från kod (t.ex. när en resurs inte finns):

@inject NavigationManager Nav

protected override async Task OnInitializedAsync()
{
    product = await Api.GetAsync(Id);
    if (product is null) Nav.NotFound(); // ny i .NET 10
}
.NET 10-nyheter för routing

Referenser

Elektroniska resurser

Böcker

Övningar

Lös övningarna självständigt. Det finns inget facit — lärandet sker i processen.

  1. Produktsida med parameter Bygg en lista med 5 hårdkodade produkter. Klick på en produkt navigerar till /produkter/{id:int} som visar detaljer.
  2. Sök med query string Bygg en söksida som accepterar ?q=...&sida=... och visar parametrarna. Lägg till en formulärknapp som ändrar URL via NavigationManager.
  3. Två layouter Skapa en AdminLayout med annan färgsättning än MainLayout. Lägg minst en sida under /admin som använder den nya layouten.
  4. Egen 404-sida Anpassa NotFound-mallen så att den visar en bild, en länk tillbaka till startsidan och loggar den misslyckade URL:en i konsolen.

Soloprojektor

Projekt 1 — Bloggportal Bygg en blogg med minst 5 hårdkodade artiklar. Startsidan listar alla artiklar med titel + ingress. Klick navigerar till /blogg/{slug} som visar hela artikeln. Inkludera NavMenu och en custom 404-sida.
Projekt 2 — Multi-layout-app (fördjupning) Skapa en app med tre olika layouter: PublicLayout (header + footer), AdminLayout (sidebar + topbar) och PrintLayout (ingen kantbar, för utskrift). Sidor placeras under olika mappar som alla har egen layout-default.

← Föregående: Data binding Nästa: Formulär & validering →