Skip to content

Shell | Getting Started

Make .NET MAUI Shell shinier with viewmodel lifecycle management, navigation, and source generation to remove boilerplate, reduce errors, and make your app testable.

Inspired by Prism Library by Dan Siegel and Brian Lagunas.

  • GitHub stars for shinyorg/mauishell
  • NuGet downloads for Shiny.Maui.Shell
Frameworks
.NET MAUI
  • Navigation service — route-based and ViewModel-based navigation with INavigator
  • Shell switching — swap the entire Shell at runtime with SwitchShell (instance or DI-resolved)
  • Dialog service — alert, confirm, prompt, and action sheet dialogs with IDialogs
  • Navigation eventsNavigating and Navigated events with source/destination ViewModel instances
  • ViewModel lifecycle — appearing/disappearing, navigation confirmation, navigation awareness, and disposal
  • Auto BindingContext — ViewModels automatically attached to page binding contexts
  • Source generation — eliminates route registration boilerplate, generates strongly-typed navigation extensions and DI registration
  • ShinyShell base class — one base class change for deterministic BindingContext assignment on the initial page
  • TestableINavigator and IDialogs are injectable and mockable for unit testing
  1. Install the NuGet package

    NuGet package Shiny.Maui.Shell
    Terminal window
    dotnet add package Shiny.Maui.Shell
  2. Configure UseShinyShell in your MauiProgram.cs

    public static class MauiProgram
    {
    public static MauiApp CreateMauiApp()
    {
    var builder = MauiApp.CreateBuilder();
    builder
    .UseMauiApp<App>()
    .UseShinyShell(x => x
    .Add<MainPage, MainViewModel>(registerRoute: false)
    .Add<AnotherPage, AnotherViewModel>("another")
    )
    .ConfigureFonts(fonts =>
    {
    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
    });
    return builder.Build();
    }
    }
  3. Update your AppShell to inherit from ShinyShell

    AppShell.xaml:

    <shiny:ShinyShell
    x:Class="MyApp.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:shiny="clr-namespace:Shiny;assembly=Shiny.Maui.Shell"
    xmlns:local="clr-namespace:MyApp"
    Title="MyApp">
    <ShellContent
    Title="Home"
    ContentTemplate="{DataTemplate local:MainPage}"
    Route="MainPage" />
    </shiny:ShinyShell>

    AppShell.xaml.cs:

    using Shiny;
    namespace MyApp;
    public partial class AppShell : ShinyShell
    {
    public AppShell()
    {
    InitializeComponent();
    }
    }
  4. Inject INavigator into your ViewModels and navigate

    using Shiny;
    public class MainViewModel(INavigator navigator)
    {
    public async Task GoToDetails()
    {
    await navigator.NavigateTo("another");
    }
    }
// Navigate by route with arguments
await navigator.NavigateTo("details", ("Id", 42));
// Navigate by ViewModel with strongly typed setup
await navigator.NavigateTo<DetailViewModel>(vm => vm.Id = 42);
// Go back with arguments
await navigator.GoBack(("Result", "saved"));
// Switch to a different Shell at runtime
await navigator.SwitchShell<AdminShell>();
claude plugin add github:shinyorg/skills/shiny-maui-shell
  1. Open the shiny-maui-shell skill file and copy its contents
  2. In your repository, create .github/copilot-instructions.md if it doesn't exist
  3. Paste the skill content into that file and save

Copilot will automatically pick up the instructions on your next chat or code completion. You can also use path-specific instructions by placing the file in .github/instructions/ with an applyTo frontmatter pattern.

View Skill