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
AppBarButtonwith aCommandBarfor primary commands andCommandBarFlyoutfor contextual toolbars. - Use the
Iconslot for 16–24 px glyphs to keep the command list easy to scan. - Toggle between
LabelPosition=CollapsedandLabelPosition=Rightdepending on whether space is constrained.
Prerequisites
- Windows App SDK / WinUI 3 project targeting Windows 10 version 1809 (build 17763) or later
Microsoft.UI.Xaml.Controlsnamespace 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.
<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="" /> </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
Labelfor 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, setFocus(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.IsOpento 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.