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

Shell & App-Wide Flyouts

Frameworks
.NET MAUI

ShinyFlyout is a pair of attached properties — StartTemplate and EndTemplate — that install a flyout over every page a host shows. Put them on a Shell, a NavigationPage, or a single page.

<Shell xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:shiny="http://shiny.net/maui/controls"
x:Class="MyApp.AppShell"
FlyoutBehavior="Disabled">
<shiny:ShinyFlyout.StartTemplate>
<DataTemplate>
<shiny:FlyoutPanel State="Hidden"
CollapsedState="Hidden"
Presentation="Overlay"
ExpandedWidth="280">
<shiny:FlyoutPanel.HeaderContent>
<Label Text="Menu" FontSize="18" FontAttributes="Bold" Padding="20,18" />
</shiny:FlyoutPanel.HeaderContent>
<VerticalStackLayout Padding="8">
<Label Text="Home" Padding="16,12" />
<Label Text="Projects" Padding="16,12" />
<Label Text="Settings" Padding="16,12" />
</VerticalStackLayout>
</shiny:FlyoutPanel>
</DataTemplate>
</shiny:ShinyFlyout.StartTemplate>
<!-- ShellContent … -->
</Shell>

Open it from anywhere with IFlyoutService:

public class ToolbarViewModel(IFlyoutService flyouts)
{
public Task OpenMenu() => flyouts.ToggleAsync();
}

Each page builds its own panel from the template. Sharing one panel instance across pages would mean re-parenting it on every navigation, which rebuilds its native views and throws away scroll position and focus.

What carries across pages is the state — a drawer left open is still open on the page you land on, and a rail stays a rail.

  • Set Shell.FlyoutBehavior="Disabled" so Shell’s own drawer stays out of the way.
  • The flyout wraps the page’s content, so a panel sits below the nav bar and above the tab bar, and Presentation="Push" pushes the page content rather than Shell’s chrome. Add Shell.NavBarIsVisible="False" to a page if the panel should run the full height of the window.
  • A page that is already a ShinyFlyoutPage is skipped — it brings its own.

The same two properties work on a NavigationPage, which is the closest thing to the old FlyoutPage + Detail = new NavigationPage(...) arrangement:

var nav = new NavigationPage(new HomePage());
ShinyFlyout.SetStartTemplate(nav, new DataTemplate(() => new FlyoutPanel
{
State = FlyoutPanelState.Hidden,
CollapsedState = FlyoutPanelState.Hidden,
Presentation = FlyoutPresentation.Overlay,
PanelContent = new NavigationMenu()
}));

Every page pushed onto that stack gets the drawer.

Setting the attached property directly on a ContentPage installs the flyout on just that page — useful when one screen needs a drawer and the rest of the app does not, without changing the page’s base class.

Because XAML applies properties in document order, a template declared above the page’s content is set while the page still has none; the install waits for the content to arrive rather than wrapping nothing.