Implementing Xamarin.Forms Shell Navigation: A Practical Guide
Learn how to set up Xamarin.Forms Shell navigation, register deep‑link routes, and validate platform‑specific styles. Follow this step‑by‑step guide to build a cross‑platform app that’s easy to maintain and performant.
03 Jul 2026, 09:13 UTC

Desired Outcome
Set up a Xamarin.Forms application that uses Shell to manage navigation, theming, and deep‑linking across Android, iOS, and UWP. After following this guide, you should be able to:
- Define a single
AppShell.xamlthat contains tabs, flyouts, and routes. - Navigate programmatically and via external URLs.
- Verify that platform‑specific styles (Material, Cupertino) are applied automatically.
- Recover to a traditional
NavigationPagestructure if needed.
Prerequisites
- Visual Studio 2022 (or later) with Xamarin workload installed.
- Target SDKs: Android 11+, iOS 13+, UWP 10.0.19041+.
- Basic knowledge of XAML and C#.
- Existing Xamarin.Forms project (Blank App template is fine).
Step‑by‑Step Setup
- Create the Shell file
// AppShell.xaml <Shell xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:MyApp" x:Class="MyApp.AppShell"> <Shell.FlyoutHeader> <Label Text="My App" FontSize="24"/> </Shell.FlyoutHeader> <ShellItem> <ShellSection Title="Home" Icon="home.png"> <ShellContent ContentTemplate="{DataTemplate local:HomePage}"/> </ShellSection> </ShellItem> <ShellItem> <ShellSection Title="About" Icon="info.png"> <ShellContent ContentTemplate="{DataTemplate local:AboutPage}"/> </ShellSection> </ShellItem>Place this file in the shared project and set its build action to
EmbeddedResourceif you useShellfrom the Xamarin.Forms assembly. - Register routes for deep linking
// In App.xaml.cs constructor Routing.RegisterRoute("about", typeof(AboutPage));Keep route names short and avoid spaces or special characters that are not URL‑safe.
- Implement navigation from code
// Example button click handler async void OnAboutClicked(object sender, EventArgs e) { await Shell.Current.GoToAsync("about"); }Use
Shell.Current.GoToAsyncfor all navigation; avoidNavigation.PushAsyncunless you need a non‑Shell stack. - Set up a custom URL scheme for deep linking
- Android: add intent filter to
AndroidManifest.xml.<intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> <data android:scheme="myapp" android:host=""/> </intent-filter> - iOS: add URL types in
Info.plist.<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLName</key> <string>myapp</string> <key>CFBundleURLSchemes</key> <array> <string>myapp</string> </array> </dict> </array> - UWP: register protocol in
Package.appxmanifest.
- Android: add intent filter to
- Test deep link on a device
adb shell am start -a android.intent.action.VIEW -d "myapp://about"On iOS, use Safari:
myapp://about. The app should open directly toAboutPage.
Validation Checks
- UI appearance: Verify that Android uses Material Design (e.g., ripple on tap) and iOS uses Cupertino (e.g., iOS navigation bar). UWP should display a Fluent UI flyout.
- Navigation stack: Press back on each platform; the app should return to the previous Shell section, not crash.
- Deep link handling: Open the URL from a browser or terminal; the correct page should appear. Check platform logs for errors (logcat, Xcode console, UWP output).
- Performance: Compare startup time and memory usage with a non‑Shell project that uses
NavigationPagefor each tab. Use Visual Studio Diagnostic Tools or Android Profiler.
Recovery Options
If you encounter issues that cannot be fixed by route or style adjustments, you can temporarily revert to a NavigationPage structure for debugging:
// In App.xaml.cs
MainPage = new NavigationPage(new HomePage());
Remember to remove this line before shipping the production build to keep the Shell‑based navigation intact.
Limitations & Future Considerations
- Xamarin.Forms is being phased out in favor of .NET MAUI. Evaluate long‑term maintenance if you plan to target new platform versions.
- Large Shell trees may increase startup time; consider lazy loading pages via route registration only when needed.
- Resource dictionaries in Shell may not cascade automatically; test theme inheritance on all platforms.
- Deep linking errors are often silent; enable verbose logging on each platform to capture failures.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.