Skip to content
Shiny Controls v1.0 - The Ultra Control Suite for .NET MAUI & BlazorO...M...G!

NavigationPage

ShinyNavigationPage is a NavigationPage. PushAsync, PopAsync, PopToRootAsync, InsertPageBefore, RemovePage, the modal stack, page lifecycle, Android’s hardware back button and Pushed/Popped/PoppedToRoot all still work, unchanged. What it adds is a bar with items on the left as well as the right.

  • NuGet downloads for Shiny.Maui.Controls
Frameworks
.NET MAUI

No platform’s native navigation bar has a left slot to give you. It belongs to the back button on iOS, on Android and in WinUI alike — and on macOS AppKit (net10.0-macos) and Linux GTK4 there is no navigation bar at all.

So the native bar is hidden and ShinyNavBar draws its own. Nothing in it touches a platform SDK, which is also what makes the overflow menu, the badges, the motion icons and the collapsing large title render identically on every MAUI head.

<shiny:ShinyNavigationPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:shiny="http://shiny.net/maui/controls"
xmlns:local="clr-namespace:MyApp"
x:Class="MyApp.MainNav"
LargeTitleDisplay="Collapsing">
<x:Arguments>
<local:InboxPage />
</x:Arguments>
</shiny:ShinyNavigationPage>

Or wherever a NavigationPage went before:

Application.Current.Windows[0].Page = new ShinyNavigationPage(new InboxPage());

Then declare the items on the page, the way ToolbarItems already are:

<ContentPage xmlns:shiny="http://shiny.net/maui/controls"
Title="Inbox"
shiny:ShinyNav.Subtitle="12 unread">
<shiny:ShinyNav.LeftItems>
<shiny:NavBarItem Icon="menu" Command="{Binding OpenDrawerCommand}" />
</shiny:ShinyNav.LeftItems>
<shiny:ShinyNav.RightItems>
<shiny:NavBarItem Icon="search" Command="{Binding SearchCommand}" />
<shiny:NavBarItem Icon="bell" Badge="3" Command="{Binding AlertsCommand}" />
<shiny:NavBarItem Text="Mark all read" Order="Secondary" Command="{Binding MarkAllCommand}" />
</shiny:ShinyNav.RightItems>
<!-- page content -->
</ContentPage>

See Items & Overflow for the full item model.

What MAUI already gives you, honoured as-is

Section titled “What MAUI already gives you, honoured as-is”

Nothing here is reinvented. The bar reads it straight off the page:

MAUI API Effect
Page.Title the bar’s title
Page.ToolbarItems drawn on the right, ahead of ShinyNav.RightItems
NavigationPage.SetHasBackButton(page, false) hides the back affordance
NavigationPage.SetBackButtonTitle(page, "Inbox") labels it
NavigationPage.SetTitleView(page, view) replaces the title outright
NavigationPage.SetTitleIconImageSource(page, src) artwork before the title
NavigationPage.SetIconColor(page, color) tints the chevron and the item artwork
BarBackground / BarBackgroundColor / BarTextColor on the navigation page, as always

A page’s existing toolbar therefore keeps working the moment you swap the host, with nothing rewritten.

LargeTitleDisplay is Inherit, None, Always or Collapsing.

<shiny:ShinyNavigationPage LargeTitleDisplay="Collapsing" />

Collapsing gives the iOS behaviour: an oversized title beneath the bar row at rest, folding into the inline title as the page scrolls. It follows the first ScrollView or ItemsView it finds in the page’s content; name a different one when a page has more than one:

<ContentPage shiny:ShinyNav.ScrollSource="{x:Reference TheList}" />

Inherit is the value that makes per-page overrides work. On the navigation page (and on the bar itself) there is nothing above to ask, so it means None; on a page it means “whatever the navigation page said” — which is what lets one page turn the large title off against a navigation page that turned it on:

<ContentPage shiny:ShinyNav.LargeTitleDisplay="None" />

Tune it with LargeTitleHeight (52), LargeTitleCollapseDistance (48) and LargeTitleFontSize. ShinyNavBar.CollapseProgress runs 0 → 1 and is bindable, so a header image can be parallaxed off the same value.

<ContentPage shiny:ShinyNav.BackButtonCommand="{Binding ConfirmLeaveCommand}" />

Nothing is popped for you — call Navigation.PopAsync() when the user confirms. Alternatively handle ShinyNavBar.BackButtonPressed and set e.Cancel = true. With neither, the bar pops.

ShinyNav.BackButtonIcon swaps the chevron for any built-in motion iconclose is the usual choice on a page pushed as a form.

  • Pages that are not a ContentPage are left entirely alone. A TabbedPage or FlyoutPage pushed onto the stack brings its own chrome, keeps its native bar, and gets no drawn bar.
  • On a ShinyContentPage the wrapper goes around PageContent, so toasts, dialogs and floating panels still float above the bar.
  • iOS edge-swipe-back keeps working. UIKit disables interactivePopGestureRecognizer whenever the navigation bar is hidden, so the page puts it back deliberately, with a delegate that allows the swipe only when there is something to pop. EnableSwipeBackGesture="False" opts out.
  • Shell cannot host a NavigationPage — that is a MAUI rule, not one of ours. In a Shell app, present this modally for a self-contained flow, or use Shell’s own navigation with ShinyTabBarBehavior and Flyout.
  • ShinyNavBar can be used on its own at the top of any layout, but it owns no navigation — the host does the popping.
claude plugin marketplace add shinyorg/skills
claude plugin install shiny@shiny

One plugin installs all 35 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.

copilot plugin marketplace add https://github.com/shinyorg/skills
copilot plugin install shiny@shiny

One plugin installs all 35 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.

View Skills Repository