/maui-shell-navigation
Guide for implementing Shell-based navigation in .NET MAUI apps. Covers AppShell setup, visual hierarchy (FlyoutItem, TabBar, Tab, ShellContent), URI-based navigation with GoToAsync, route registration, query parameters, back navigation, flyout and tab configuration, navigation
$ npx -y skills add managedcode/dotnet-skills --skill maui-shell-navigation --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/maui-shell-navigation
Context preview
The summary Claude sees to decide when to auto-load this skill.
Guide for implementing Shell-based navigation in .NET MAUI apps. Covers AppShell setup, visual hierarchy (FlyoutItem, TabBar, Tab, ShellContent), URI-based navigation with GoToAsync, route registration, query parameters, back navigation, flyout and tab configuration, navigation
SKILL.md
maui-shell-navigation.SKILL.mdname: maui-shell-navigation
description: >-
Guide for implementing Shell-based navigation in .NET MAUI apps. Covers AppShell
setup, visual hierarchy (FlyoutItem, TabBar, Tab, ShellContent), URI-based navigation
with GoToAsync, route registration, query parameters, back navigation, flyout and
tab configuration, navigation events, and navigation guards.
Use when: setting up Shell navigation, adding tabs or flyout menus, navigating between
pages with GoToAsync, passing parameters between pages, registering routes, customizing
back button behavior, or guarding navigation with confirmation dialogs.
Do not use for: deep linking from external URLs (see .NET MAUI deep linking
documentation), data binding on pages (use maui-data-binding), dependency injection
setup (use maui-dependency-injection), or NavigationPage-only apps that don't use Shell.
license: MIT
.NET MAUI Shell Navigation
Implement page navigation in .NET MAUI apps using Shell. Shell provides URI-based navigation, a flyout menu, tab bars, and a four-level visual hierarchy — all configured declaratively in XAML.
When to Use
- Setting up top-level app navigation with tabs or a flyout menu
- Navigating between pages programmatically with `GoToAsync`
- Passing data between pages via query parameters or object parameters
- Registering detail-page routes for push navigation
- Guarding navigation with confirmation dialogs (e.g., unsaved changes)
- Customizing back button behavior per page
When Not to Use
- Deep linking from external URLs or app links — see [.NET MAUI deep linking docs](https://learn.microsoft.com/dotnet/maui/fundamentals/app-links)
- Data binding on navigation target pages — use `maui-data-binding`
- Dependency injection for pages and view models — use `maui-dependency-injection`
- Apps using `NavigationPage` without Shell (different navigation API)
Inputs
- A .NET MAUI project with `AppShell.xaml` as the root shell
- Pages (`ContentPage`) to navigate between
- Route names for detail pages not in the visual hierarchy
Rules That Change the Answer
These are the Shell-specific decisions that are easy to get wrong. Apply them whenever they are relevant to what the user asked.
| Situation | Do this | Not this | |---|---|---| | Declaring pages in `AppShell.xaml` | With `xmlns:views="clr-namespace:MyApp.Views"` declared: `<ShellContent ContentTemplate="{DataTemplate views:MyPage}" />` — the page is created on first navigation | `<ShellContent><views:MyPage /></ShellContent>`, which constructs **every** page at startup | | Navigating to a page not in the visual hierarchy | `Routing.RegisterRoute("details", typeof(DetailsPage))` first | Calling `GoToAsync("details")` unregistered — it throws at runtime | | Receiving navigation parameters | Implement `IQueryAttributable` on the **ViewModel** | Implementing it on the Page, which splits state from the BindingContext | | Passing a whole object | `ShellNavigationQueryParameters` | Serialising the object into the query string | | Any `GoToAsync` call | `await` it | Fire-and-forget — exceptions are swallowed and navigation races | | Confirming before back navigation | `ShellNavigatingEventArgs.GetDeferral()` … `deferral.Complete()` | Blocking synchronously on the dialog task | | Detecting back navigation | Check `e.Source == ShellNavigationSource.Pop` | Assuming every navigation is a back action |
**Do not** propose `NavigationPage` / `PushAsync` solutions for a Shell app, and do not restructure a working `AppShell` hierarchy unless the user asked.
**Answer narrowly, but completely.** Staying on topic does not mean being terse. When you show a navigation change, include the pieces needed to run it: the `AppShell.xaml` markup *and* the `Routing.RegisterRoute` call, or the `GoToAsync` call *and* the receiving `IQueryAttributable` / `[QueryProperty]` code. Where two approaches are both valid (query string vs `ShellNavigationQueryParameters`), show both and say when each fits — a single snippet the user still has to complete is a worse answer.
Shell Visual Hierarchy
Shell uses a four-level hierarchy. Each level wraps the one below it:
Shell
├── FlyoutItem / TabBar (top-level grouping)
│ ├── Tab (bottom-tab grouping)
│ │ ├── ShellContent (page slot → ContentPage)
│ │ └── ShellContent (multiple = top tabs)
│ └── Tab
└── FlyoutItem / TabBar
- **FlyoutItem** — appears in the flyout menu; contains `Tab` children
- **TabBar** — bottom tab bar with no flyout entry
- **Tab** — groups `ShellContent`; multiple children produce top tabs
- **ShellContent** — each points to a `ContentPage`
Implicit Conversion
You can omit intermediate wrappers. Shell auto-wraps:
| You write | Shell creates | |------------------------------|---------------------------------------| | `ShellContent` only | `FlyoutItem > Tab > ShellContent` | | `Tab` only | `FlyoutItem > Tab` | | `ShellContent` in `TabBar` | `TabBar > Tab > ShellContent` |
Workflow: Set Up AppShell
1. Define `AppShell.xaml` inheriting from `Shell` 2. Add `FlyoutItem` or `TabBar` elements for top-level navigation 3. Add `Tab` elements for bottom tabs; nest multiple `ShellContent` for top tabs 4. **Always use `ContentTemplate`** with `DataTemplate` so pages load on demand 5. **Give every `ShellContent` an explicit `Route`** (see below) 6. Register detail-page routes in the `AppShell` constructor
> **Set `Route=` on every `ShellContent`.** If you omit it, MAUI auto-generates a > name from a shared counter — `Routing.cs` produces `D_FAULT_{TypeName}{n}`. A real > shell with three unnamed `ShellContent` elements yields routes like > `D_FAULT_ShellContent2` and `D_FAULT_ShellContent5`: the numbers are not > sequential, they depend on how many Shell elements were constructed first, and they > shift when you reorder or
Read more
name: maui-shell-navigation description: >- Guide for implementing Shell-based navigation in .NET MAUI apps. Covers AppShell setup, visual hierarchy (FlyoutItem, TabBar, Tab, ShellContent), URI-based navigation with GoToAsync, route registration, query parameters, back navigation, flyout and tab configuration, navigation events, and navigation guards. Use when: setting up Shell navigation, adding tabs or flyout menus, navigating between pages with GoToAsync, passing parameters between pages, registering routes, customizing back button behavior, or guarding navigation with confirmation dialogs. Do not use for: deep linking from external URLs (see .NET MAUI deep linking documentation), data binding on pages (use maui-data-binding), dependency injection setup (use maui-dependency-injection), or NavigationPage-only apps that don't use Shell. license: MIT
.NET MAUI Shell Navigation
Implement page navigation in .NET MAUI apps using Shell. Shell provides URI-based navigation, a flyout menu, tab bars, and a four-level visual hierarchy — all configured declaratively in XAML.
When to Use
- Setting up top-level app navigation with tabs or a flyout menu
- Navigating between pages programmatically with `GoToAsync`
- Passing data between pages via query parameters or object parameters
- Registering detail-page routes for push navigation
- Guarding navigation with confirmation dialogs (e.g., unsaved changes)
- Customizing back button behavior per page
When Not to Use
- Deep linking from external URLs or app links — see [.NET MAUI deep linking docs](https://learn.microsoft.com/dotnet/maui/fundamentals/app-links)
- Data binding on navigation target pages — use `maui-data-binding`
- Dependency injection for pages and view models — use `maui-dependency-injection`
- Apps using `NavigationPage` without Shell (different navigation API)
Inputs
- A .NET MAUI project with `AppShell.xaml` as the root shell
- Pages (`ContentPage`) to navigate between
- Route names for detail pages not in the visual hierarchy
Rules That Change the Answer
These are the Shell-specific decisions that are easy to get wrong. Apply them whenever they are relevant to what the user asked.
| Situation | Do this | Not this | |---|---|---| | Declaring pages in `AppShell.xaml` | With `xmlns:views="clr-namespace:MyApp.Views"` declared: `<ShellContent ContentTemplate="{DataTemplate views:MyPage}" />` — the page is created on first navigation | `<ShellContent><views:MyPage /></ShellContent>`, which constructs **every** page at startup | | Navigating to a page not in the visual hierarchy | `Routing.RegisterRoute("details", typeof(DetailsPage))` first | Calling `GoToAsync("details")` unregistered — it throws at runtime | | Receiving navigation parameters | Implement `IQueryAttributable` on the **ViewModel** | Implementing it on the Page, which splits state from the BindingContext | | Passing a whole object | `ShellNavigationQueryParameters` | Serialising the object into the query string | | Any `GoToAsync` call | `await` it | Fire-and-forget — exceptions are swallowed and navigation races | | Confirming before back navigation | `ShellNavigatingEventArgs.GetDeferral()` … `deferral.Complete()` | Blocking synchronously on the dialog task | | Detecting back navigation | Check `e.Source == ShellNavigationSource.Pop` | Assuming every navigation is a back action |
**Do not** propose `NavigationPage` / `PushAsync` solutions for a Shell app, and do not restructure a working `AppShell` hierarchy unless the user asked.
**Answer narrowly, but completely.** Staying on topic does not mean being terse. When you show a navigation change, include the pieces needed to run it: the `AppShell.xaml` markup *and* the `Routing.RegisterRoute` call, or the `GoToAsync` call *and* the receiving `IQueryAttributable` / `[QueryProperty]` code. Where two approaches are both valid (query string vs `ShellNavigationQueryParameters`), show both and say when each fits — a single snippet the user still has to complete is a worse answer.
Shell Visual Hierarchy
Shell uses a four-level hierarchy. Each level wraps the one below it:
Shell ├── FlyoutItem / TabBar (top-level grouping) │ ├── Tab (bottom-tab grouping) │ │ ├── ShellContent (page slot → ContentPage) │ │ └── ShellContent (multiple = top tabs) │ └── Tab └── FlyoutItem / TabBar
- **FlyoutItem** — appears in the flyout menu; contains `Tab` children
- **TabBar** — bottom tab bar with no flyout entry
- **Tab** — groups `ShellContent`; multiple children produce top tabs
- **ShellContent** — each points to a `ContentPage`
Implicit Conversion
You can omit intermediate wrappers. Shell auto-wraps:
| You write | Shell creates | |------------------------------|---------------------------------------| | `ShellContent` only | `FlyoutItem > Tab > ShellContent` | | `Tab` only | `FlyoutItem > Tab` | | `ShellContent` in `TabBar` | `TabBar > Tab > ShellContent` |
Workflow: Set Up AppShell
1. Define `AppShell.xaml` inheriting from `Shell` 2. Add `FlyoutItem` or `TabBar` elements for top-level navigation 3. Add `Tab` elements for bottom tabs; nest multiple `ShellContent` for top tabs 4. **Always use `ContentTemplate`** with `DataTemplate` so pages load on demand 5. **Give every `ShellContent` an explicit `Route`** (see below) 6. Register detail-page routes in the `AppShell` constructor
> **Set `Route=` on every `ShellContent`.** If you omit it, MAUI auto-generates a > name from a shared counter — `Routing.cs` produces `D_FAULT_{TypeName}{n}`. A real > shell with three unnamed `ShellContent` elements yields routes like > `D_FAULT_ShellContent2` and `D_FAULT_ShellContent5`: the numbers are not > sequential, they depend on how many Shell elements were constructed first, and they > shift when you reorder or
Stop explaining .NET to your AI. Start building. We've all been there: asking Claude to use Entity Framework, only to get EF6 patterns in a .NET 8 project. Explaining to Copilot that Blazor Server and Blazor WebAssembly aren't the same thing.
Repo: managedcode/dotnet-skills
Other skills on dotnet-skills.
- /aspnet-core
Build, debug, modernize, or review ASP.NET Core applications with correct hosting, middleware, security, configuration, logging, and deployment patterns on current .NET. USE FOR: working on ASP.NET Core apps, services, or middleware; changing auth, routing, configuration,
Open skill - /aspire
Build, upgrade, and operate Aspire 13.4.x C# or TypeScript application hosts with the current CLI, AppHost, ServiceDefaults, integrations, dashboard, testing, MCP, and deployment patterns for distributed apps. USE FOR: Aspire.AppHost.Sdk, Aspire.Hosting.*,
Open skill - /azure-functions
Build, review, or migrate Azure Functions in .NET with correct execution model, isolated worker setup, bindings, DI, and Durable Functions patterns. USE FOR: working on Azure Functions in .NET; migrating from the in-process model to the isolated worker model; adding Durable
Open skill - /blazor
Build and review Blazor applications across server, WebAssembly, web app, and hybrid scenarios with correct component design, state flow, rendering, and hosting choices. USE FOR: building interactive web UIs with C# instead of JavaScript; choosing between Server, WebAssembly, or
Open skill - /entity-framework6
Maintain or migrate EF6-based applications with realistic guidance on what to keep, what to modernize, and when EF Core is or is not the right next step. USE FOR: EF6 codebases; runtime versus ORM migration decisions; EDMX, code-first, ObjectContext, and legacy data-access
Open skill - /entity-framework-core
Design, tune, or review EF Core data access with proper modeling, migrations, query translation, performance, and lifetime management for modern .NET applications. USE FOR: DbContext, migrations, model configuration, EF queries, tracking, loading, performance, transactions, and
Open skill

