.NET MAUI

Shell Navigation

7 question(s)

What is .NET MAUI Shell?

Beginner
Shell is an app container that provides a common navigation structure: a flyout menu, bottom tabs, top tabs, and URI-based routing. It reduces boilerplate compared to manually composing NavigationPage and TabbedPage, and centralizes navigation, search handlers, and styling.
<Shell xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
       x:Class="MyApp.AppShell">
    <FlyoutItem Title="Home">
        <ShellContent ContentTemplate="{DataTemplate local:HomePage}" />
    </FlyoutItem>
</Shell>
Real-world example A team gets a flyout, tabs, and deep-link routing for free by defining one AppShell instead of wiring navigation pages by hand.

Common follow-ups: What navigation styles does Shell offer? | How do you register routes?

Navigation Flyout Tabs

How do you navigate between pages using Shell?

Beginner
Call Shell.Current.GoToAsync with a route. Absolute routes (starting //) reset the navigation stack to a registered top-level route; relative routes push onto the current stack. Routes are registered via Routing.RegisterRoute or implicitly by ShellContent.
await Shell.Current.GoToAsync("details");        // push
await Shell.Current.GoToAsync("//home");          // reset to root
await Shell.Current.GoToAsync("..");              // go back
Real-world example Tapping a list item pushes a details route, and a logout action uses //login to clear the stack and return to sign-in.

Common follow-ups: What's the difference between // and relative routes? | How do you go back?

Navigation Routing Shell Navigation

How do you pass parameters during Shell navigation?

Intermediate
Pass a dictionary to GoToAsync and receive it via query properties. Decorate the target page or view model with [QueryProperty] (or implement IQueryAttributable) so MAUI injects the values. Objects can be passed in-memory via the dictionary; primitives can also go in the query string.
await Shell.Current.GoToAsync("details",
    new Dictionary<string, object> { ["Item"] = selected });

[QueryProperty(nameof(Item), "Item")]
public partial class DetailsPage : ContentPage
{ public Product Item { get; set; } }
Real-world example A catalog passes the selected product object straight to the details page's view model without re-fetching it from the server.

Common follow-ups: IQueryAttributable vs QueryProperty? | Can you pass complex objects?

Navigation Routing Data Binding & MVVM

How do you register routes for pages not in the Shell visual hierarchy?

Intermediate
Detail pages that aren't tabs or flyout items must be registered with Routing.RegisterRoute("route", typeof(Page)) in AppShell's constructor. Then GoToAsync("route") can push them. This keeps deep, contextual pages out of the top-level navigation while remaining routable.
public AppShell()
{
    InitializeComponent();
    Routing.RegisterRoute("details", typeof(DetailsPage));
    Routing.RegisterRoute("edit", typeof(EditPage));
}
Real-world example An order-details page and its edit page are registered as routes so they can be pushed from the orders tab but never appear as tabs themselves.

Common follow-ups: Where do you register routes? | What happens if a route is unregistered?

Routing Navigation Shell Navigation

How do you configure tabs and flyout items in Shell?

Intermediate
Use TabBar with Tab/ShellContent for bottom tabs, and FlyoutItem for flyout entries. Nesting Tabs inside a FlyoutItem creates top tabs. FlyoutBehavior controls whether the flyout is shown, disabled, or locked. Icons and titles are set per item.
<TabBar>
    <Tab Title="Feed" Icon="feed.png">
        <ShellContent ContentTemplate="{DataTemplate local:FeedPage}" />
    </Tab>
    <Tab Title="Profile" Icon="user.png">
        <ShellContent ContentTemplate="{DataTemplate local:ProfilePage}" />
    </Tab>
</TabBar>
Real-world example A social app shows Feed and Profile as bottom tabs while settings live in a flyout, all declared in AppShell.

Common follow-ups: How do you make top tabs? | What is FlyoutBehavior?

Tabs Flyout Navigation

How do you handle navigation lifecycle and prevent back navigation in Shell?

Advanced
Implement IQueryAttributable for parameter handling, and override OnNavigating/OnNavigated or handle Shell.Navigating to inspect or cancel navigation (e.g., unsaved changes). Set args.Cancel() in the Navigating event, or use OnBackButtonPressed on a page to intercept hardware back.
protected override void OnNavigating(ShellNavigatingEventArgs args)
{
    if (HasUnsavedChanges && args.CanCancel)
        args.Cancel();
    base.OnNavigating(args);
}
Real-world example An edit screen prompts 'Discard changes?' by cancelling navigation when the user tries to leave with a dirty form.

Common follow-ups: How do you intercept the hardware back button? | Which event fires before navigation?

Navigation App Lifecycle Shell Navigation

How do you implement deep linking with Shell routes?

Advanced
Shell's URI routing maps external links to route hierarchies. Register routes, then map incoming platform deep links (Android intent filters, iOS Universal Links) to a GoToAsync call with the corresponding route and parameters. The route path can encode navigation depth like //home/orders/details?id=42.
// From platform deep-link handler
await Shell.Current.GoToAsync($"//home/orders/details?id={orderId}");
Real-world example Tapping a push-notification link opens the app directly on order #42's details page by translating the payload into a Shell route.

Common follow-ups: How do routes encode hierarchy? | Where do platform deep links get handled?

Routing Platform Integration Navigation