xaml-csharp-development-skill-for-avalonia

Focus and Keyboard Navigation

Table of Contents

  1. Scope and APIs
  2. Focus and Navigation Model
  3. Authoring Patterns
  4. Best Practices
  5. Troubleshooting

Scope and APIs

Primary APIs:

Important members:

Reference source files:

Focus and Navigation Model

Focus is owned by the current TopLevel.

Practical model:

Authoring Patterns

Basic tab order

<StackPanel>
  <TextBox Name="First" KeyboardNavigation.TabIndex="0" />
  <TextBox Name="Second" KeyboardNavigation.TabIndex="1" />
  <Button Content="Submit" KeyboardNavigation.TabIndex="2" />
</StackPanel>

Container navigation mode

<StackPanel KeyboardNavigation.TabNavigation="Cycle">
  <TextBox />
  <TextBox />
</StackPanel>

Programmatic traversal

using Avalonia.Controls;
using Avalonia.Input;

if (TopLevel.GetTopLevel(this)?.FocusManager is FocusManager fm)
{
    fm.TryMoveFocus(NavigationDirection.Next);
}

Directional override with XYFocus

<Button x:Name="LeftButton" XYFocus.Right="{Binding #RightButton}" />
<Button x:Name="RightButton" XYFocus.Left="{Binding #LeftButton}" />

Access key visibility and labels

<StackPanel>
  <Label Content="_Name" Target="{Binding #NameBox}" />
  <TextBox x:Name="NameBox" />
</StackPanel>

Best Practices

Troubleshooting

  1. Focus cannot move into a control:
    • Focusable is false.
    • IsEffectivelyEnabled is false.
    • Control is not visible.
  2. Tab key skips expected elements:
    • KeyboardNavigation.IsTabStop disabled.
    • KeyboardNavigation.TabNavigation on ancestor is None or restrictive.
  3. Directional keys move unpredictably:
    • Missing XYFocus overrides in sparse layouts.
    • Flow direction (RTL) changes effective left/right behavior.
  4. Access keys do not appear or act:
    • Missing _ marker in AccessText/label content.
    • Focus is not inside the active input root.

XAML-First and Code-Only Usage

Default mode:

XAML-first complete example:

<StackPanel xmlns="https://github.com/avaloniaui"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            KeyboardNavigation.TabNavigation="Cycle"
            Spacing="6">
  <TextBox x:Name="FirstNameBox" KeyboardNavigation.TabIndex="0" />
  <TextBox x:Name="LastNameBox" KeyboardNavigation.TabIndex="1" />
  <Button x:Name="SaveButton" KeyboardNavigation.TabIndex="2" Content="Save" />
</StackPanel>

Code-only alternative (on request):

using Avalonia.Controls;
using Avalonia.Input;

KeyboardNavigation.SetTabNavigation(formPanel, KeyboardNavigationMode.Cycle);
KeyboardNavigation.SetTabIndex(firstNameBox, 0);
KeyboardNavigation.SetTabIndex(lastNameBox, 1);
KeyboardNavigation.SetTabIndex(saveButton, 2);

TopLevel.GetTopLevel(saveButton)?.FocusManager?.Focus(firstNameBox, NavigationMethod.Tab);