WPF Standard Control Demo App › Label
Label Display
Label shows a caption, usually for an input field, and can move the keyboard focus to that field with an access key.
Where the access key moves the focus
Label derives from ContentControl. By default it does not take the focus itself: Focusable and IsTabStop were both False, and Tab from a TextBox before a Label went straight to the TextBox after it. What it does is pass the focus on: Target is the element that receives the focus when the Label’s access key is pressed.
With _Name(Press Alt+N) and _Age(Press Alt+A), processing the access keys N and A with AccessKeyManager.ProcessKey moved the focus to the Name and Age text boxes (a physical key press was not measured). Without Target, the access key of _Plain left the focus where it was, so set Target on every caption with an access key. A different focus scope is not a problem: a Label whose Target was a TextBox inside a ToolBar moved the focus into it. Other controls work as targets too: the access key moved the focus to a ComboBox itself, and to the text box inside an editable ComboBox or a DatePicker.
Target does not name the field for screen readers
The documentation of the Label class says that setting the target makes UI Automation use the label’s text as the name of the target. On .NET 10 it did not. Read through the UI Automation client API, which screen readers use, the Name TextBox had an empty name and no LabeledBy. This matches an open report, dotnet/wpf#9185.
Name the field separately. Setting AutomationProperties.LabeledBy to the Label on the field did work: the Age TextBox was then named “Age(Press Alt+A)”.
| case | measured |
|---|---|
| base class / Focusable, IsTabStop / Padding / content alignment | ContentControl / False, False / 5,5,5,5 / Left, Top |
| TextBox, Label, TextBox: Tab from the first TextBox goes to | the second TextBox |
| demo Target labels: focus after access key N / A | Name TextBox / Age TextBox |
| Name TextBox, read by a UI Automation client: name / LabeledBy | (empty) / none |
| Age TextBox, AutomationProperties.LabeledBy set by hand: name / LabeledBy | Age(Press Alt+A) / Age(Press Alt+A) |
| Label "_Plain" without Target: focus after access key P | Other (unchanged) |
| Target is a TextBox inside a ToolBar (own focus scope): focus after access key S | the TextBox in the ToolBar |
| string Content on one line: height | 25.96 |
| string Content with a line break: height | 41.92 |
| access key, Target ComboBox / editable ComboBox / DatePicker: focus goes to | ComboBox / TextBox / DatePickerTextBox |
Defaults, access keys, Target, and UI Automation. Measured on .NET 10 / Windows 11.
The caption itself
A string content is shown with access keys recognized: the character after an underscore becomes the access key, and the underscore itself is hidden. The article linked below covers this, and how to show an underscore. A string with a line break is shown on two lines: the Label was 25.96 high with one line and 41.92 with two. The content can also be any element, such as an icon and text together.
Padding defaults to 5 on every side, and HorizontalContentAlignment and VerticalContentAlignment default to Left and Top. For text that needs no access key, use a TextBlock; the article linked below measures what many Labels cost.
Trying it in the demo app

The Label page of the demo app has sections for Target, the content, and the Control properties Padding, the font properties, Background, Foreground, the border, and the content alignment. The Target section has the two pairs _Name(Press Alt+N) and _Age(Press Alt+A), and the content section binds the caption to a multi-line text box, so a line break in the text gives a Label of two lines. The “Show Code” link under each section displays its XAML. The following XAML is the Target section (LabelUsageControl.xaml), with the styles and the surrounding GroupBox left out and the namespace declarations added:
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label x:Name="TargetNameLabel" Grid.Row="0" Grid.Column="0"
Content="_Name(Press Alt+N)"
Target="{Binding ElementName=TargetNameTextBox}" />
<TextBox x:Name="TargetNameTextBox" Grid.Row="0" Grid.Column="1" />
<Label x:Name="TargetAgeLabel" Grid.Row="1" Grid.Column="0"
Content="_Age(Press Alt+A)"
Target="{Binding ElementName=TargetAgeTextBox}" />
<TextBox x:Name="TargetAgeTextBox" Grid.Row="1" Grid.Column="1" />
</Grid>
Related controls and articles
- TextBlock — lighter text without access keys or a template.
- TextBox — the most common
Targetof a Label. - Why WPF Label Hides Underscores and How to Fix It — access keys in a Label’s text, and showing an underscore.
- Why WPF Slows Down with Many Labels and When to Switch to TextBlock — the cost of many Labels compared with TextBlocks.
Source code and how it was measured
Every behavior on this page was measured by running it on .NET 10 / Windows 11, using LabelDemoScene in this site’s screenshot tool. Access keys were sent through AccessKeyManager.ProcessKey, which processes the given access key as if its key-down had been passed to the access key manager (an API call, not a physical Alt+key press), and Tab through WPF’s input manager, the same path as keys typed on a keyboard. UI Automation names were read through the UI Automation client API, which screen readers also use, from a thread other than the window’s UI thread in the same process. Sizes are the values on the measuring machine.