Skip to main content

Open-WebUI-Functions is here! New Pipelines, Filters, and more. Learn more

WinUI AppBarButton Patterns

AppBarButton surfaces high-value commands inside a CommandBar or CommandBarFlyout. This guide shows how to enable keyboard-friendly flyouts, craft reusable templates, and keep icons aligned with fluent design guidance.

Learn more

Overview

  • Pair AppBarButton with a CommandBar for primary commands and CommandBarFlyout for contextual toolbars.
  • Use the Icon slot for 16–24 px glyphs to keep the command list easy to scan.
  • Toggle between LabelPosition=Collapsed and LabelPosition=Right depending on whether space is constrained.

Prerequisites

  • Windows App SDK / WinUI 3 project targeting Windows 10 version 1809 (build 17763) or later
  • Microsoft.UI.Xaml.Controls namespace available in your view
  • Input focus management enabled if you host text fields inside flyouts

Create interactive flyouts

The Flyout of an AppBarButton appears when the button is invoked and can host any XAML content (lists, sliders, forms, and more).

Set AllowFocusOnInteraction="True" on the button when the flyout contains text inputs so that the focus moves into the popup instead of closing it immediately.

<AppBarButton AllowFocusOnInteraction="True">
<AppBarButton.Flyout>
<Flyout>
<StackPanel>
<TextBox />
</StackPanel>
</Flyout>
</AppBarButton.Flyout>
</AppBarButton>

Reusable command template

Create a template that highlights primary actions and matches your brand palette. Apply it from CommandBar.Resources so every AppBarButton in the bar inherits the same look.

example.xaml
<CommandBar x:Name="CommandBar" Grid.Column="1" HorizontalAlignment="Right" Margin="20,6,10,4">
<CommandBar.Resources>
<ControlTemplate TargetType="AppBarButton" x:Key="AppBarButtonPrimaryTemplate">
<Grid x:Name="RootGrid">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="GridButton"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightListAccentHighBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="GridButton"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightListAccentMediumBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="GridButton"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightListAccentLowBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid x:Name="GridButton" CornerRadius="4"
Background="{TemplateBinding Background}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Margin="2,6,2,0">
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
MinHeight="35"
Width="65">
<ContentPresenter Content="{TemplateBinding Icon}" MinHeight="35"
HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- If IsEnabled = false, gray it out here too -->
<ContentPresenter.Foreground>
<SolidColorBrush
Color="{Binding Foreground.Color, RelativeSource={RelativeSource TemplatedParent}}"
Opacity="{Binding IsEnabled, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToOpacityConverter}}" />
</ContentPresenter.Foreground>
</ContentPresenter>
<TextBlock Text="{TemplateBinding Label}"
Visibility="{Binding ElementName=CommandBar, Path=IsOpen}"
TextWrapping="Wrap" TextAlignment="Center"
VerticalAlignment="Top"
HorizontalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}" Margin="0,-7,0,0">
<!-- If IsEnabled = false, gray it out here too -->
<TextBlock.Foreground>
<SolidColorBrush
Color="{Binding Foreground.Color, RelativeSource={RelativeSource TemplatedParent}}"
Opacity="{Binding IsEnabled, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToOpacityConverter}}" />
</TextBlock.Foreground>
</TextBlock>
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
</CommandBar.Resources>
<!-- CommandBar -->
<CommandBar.PrimaryCommands>
<AppBarButton Click="{x:Bind Click}"
BorderThickness="1"
Template="{StaticResource AppBarButtonPrimaryTemplate}">
<AppBarButton.Icon>
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE9F9;" />
</AppBarButton.Icon>
</AppBarButton>
</CommandBar.PrimaryCommands>
</CommandBar>

Keep template visuals subtle. Overly strong background colors can make the command bar harder to scan, especially in compact or overflow modes.

Accessibility checklist

  • Provide a concise Label for every button; screen readers voice this text even when the label is hidden visually.
  • Reserve keyboard accelerators for high-value commands and document them in the tooltip or flyout.
  • When using Flyout, set Focus(FocusState.Programmatic) on the first actionable element to help keyboard users.

Testing tips

  • Switch the app into tablet mode to validate that touch hit targets remain large enough.
  • Toggle CommandBar.IsOpen to ensure labels and chevrons animate smoothly across visual states.
  • Exercise overflow scenarios by narrowing the window until commands spill over; verify icons and automation properties survive the move.