Build accessible apps with semantic properties

Semantics for accessibility is concerned with building experiences that make your apps inclusive for people who use technology in a wide range of environments and approach your UI with a range of needs and experiences. In many situations, legal requirements for accessibility may provide an impetus for developers to address accessibility issues. Regardless, it's advisable to build inclusive and accessible apps so that your apps reach the largest possible audience.

The Web Content Accessibility Guidelines (WCAG) are the global accessibility standard and legal benchmark for web and mobile. These guidelines describe the various ways in which apps can be made more perceivable, operable, understandable, and robust, for all.

Many user accessibility needs are met by assistive technology products installed by the user or by tools and settings provided by the operating system. This includes functionality such as screen readers, screen magnification, and high-contrast settings.

Screen readers typically provide auditory descriptions of controls that are displayed on the screen. These descriptions help users navigate through the app and provide references to controls, such as images, that have no input or text. Screen readers are often controlled through gestures on the touchscreen, trackpad, or keyboard. For information about enabling screen readers, see Enable screen readers.

Operating systems have their own screen readers with their own unique behavior and configuration. For example, most screen readers read the text associated with a control when it receives focus, enabling users to orient themselves as they navigate through the app. However, some screen readers can also read the entire app user interface when a page appears, which enables the user to receive all of the page's available informational content before attempting to navigate it.

Most screen readers will automatically read any text associated with a control that receives accessibility focus. This means that controls, such as Label or Button, that have a Text property set will be accessible for the user. However, Image, ImageButton, ActivityIndicator, and others might not be in the accessibility tree because no text is associated with them.

.NET Multi-platform App UI (.NET MAUI) supports two approaches to providing access to the accessibility experience of the underlying platform. Semantic properties are the .NET MAUI approach to providing accessibility values in apps, and are the recommended approach. Automation properties are the Xamarin.Forms approach to providing accessibility values in apps, and have been superseded by semantic properties. In both cases, the default accessibility order of controls is the same order in which they're listed in XAML or added to the layout. However, different layouts might have additional factors that influence accessibility order. For example, the accessibility order of StackLayout is also based on its orientation, and the accessibility order of Grid is based on its row and column arrangement. For more information about content ordering, see Meaningful Content Ordering on the Xamarin blog.

Note

When a WebView displays a website that's accessible, it will also be accessible in a .NET MAUI app. Conversely, when a WebView displays a website that's not accessible, it won't be accessible in a .NET MAUI app.

Semantic properties

Semantic properties are used to define information about which controls should receive accessibility focus and which text should be read aloud to the user. Semantic properties are attached properties that can be added to any element to set the underlying platform accessibility APIs.

Important

Semantic properties don't try to force equivalent behavior on each platform. Instead, they rely on the accessibility experience provided by each platform.

The SemanticProperties class defines the following attached properties:

  • Description, of type string, which represents a description that will be read aloud by the screen reader. For more information, see Description.
  • Hint, of type string, which is similar to Description, but provides additional context such as the purpose of a control. For more information, see Hint.
  • HeadingLevel, of type SemanticHeadingLevel, which enables an element to be marked as a heading to organize the UI and make it easier to navigate. For more information, see Heading levels.

These attached properties set platform accessibility values so that a screen reader can speak about the element. For more information about attached properties, see Attached properties.

Description

The Description attached property represents a short, descriptive string that a screen reader uses to announce an element. This property should be set for elements that have a meaning that's important for understanding the content or interacting with the user interface. Setting this property can be accomplished in XAML:

<Image Source="dotnet_bot.png"
       SemanticProperties.Description="Cute dot net bot waving hi to you!" />

Alternatively, it can be set in C#:

Image image = new Image { Source = "dotnet_bot.png" };
SemanticProperties.SetDescription(image, "Cute dot net bot waving hi to you!");

In addition, the SetValue method can also be used to set the Description attached property:

image.SetValue(SemanticProperties.DescriptionProperty, "Cute dot net bot waving hi to you!");

The accessibility information for an element can also be defined on another element. For example, a Label next to an Switch can be used to describe what the Switch represents. This can be accomplished in XAML as follows:

<Label x:Name="label"
       Text="Enable dark mode: " />
<Switch SemanticProperties.Description="{Binding Source={x:Reference label} Path=Text}" />

Alternatively, it can be set in C# as follows:

Label label = new Label
{
    Text = "Enable dark mode: "
};
Switch mySwitch = new Switch();
SemanticProperties.SetDescription(mySwitch, label.Text);

Warning

  • Avoid setting the Description attached property on a Label. This will stop the Text property being spoken by the screen reader. This is because the visual text should ideally match the text read aloud by the screen reader.
  • Avoid setting the Description attached property on an Entry or Editor on Android. Doing so will stop Talkback actions functioning. Instead, use the Placeholder property or the Hint attached property.
  • On iOS, if you set the Description property on any control that has children the screen reader will be unable to reach the children. This is because iOS doesn't provide accessibility features that allow the navigation from a parent element into a child element.

Hint

The Hint attached property represents a string that provides additional context to the Description attached property, such as the purpose of a control. Setting this property can be accomplished in XAML:

<Image Source="like.png"
       SemanticProperties.Description="Like"
       SemanticProperties.Hint="Like this post." />

Alternatively, it can be set in C#:

Image image = new Image { Source = "like.png" };
SemanticProperties.SetDescription(image, "Like");
SemanticProperties.SetHint(image, "Like this post.");

In addition, the SetValue method can also be used to set the Hint attached property:

image.SetValue(SemanticProperties.HintProperty, "Like this post.");

On Android, this property behaves slightly differently depending on the control it's attached to. For example, for controls without text values, such as Switch and CheckBox, the controls will display the hint with the control. However, for controls with text values, the hint is not displayed and is read after the text value.

Warning

The Hint property conflicts with the Entry.Placeholder property on Android, which both map to the same platform property. Therefore, setting a different Hint value to the Entry.Placeholder value isn't recommended.

Heading levels

The HeadingLevel attached property enables an element to be marked as a heading to organize the UI and make it easier to navigate. Some screen readers enable users to quickly jump between headings.

Headings have a level from 1 to 9, and are represented by the SemanticHeadingLevel enumeration, which defines None, and Level1 through Level9 members.

Important

While Windows offers 9 levels of headings, Android and iOS only offer a single heading. Therefore, when HeadingLevel is set on Windows it maps to the correct heading level. However, when set on Android and iOS it maps to a single heading level.

The following example demonstrates setting this attached property:

<Label Text="Get started with .NET MAUI"
       SemanticProperties.HeadingLevel="Level1" />
<Label Text="Paragraphs of text go here." />
<Label Text="Installation"
       SemanticProperties.HeadingLevel="Level2" />
<Label Text="Paragraphs of text go here." />    
<Label Text="Build your first app"
       SemanticProperties.HeadingLevel="Level3" />
<Label Text="Paragraphs of text go here." />     
<Label Text="Publish your app"
       SemanticProperties.HeadingLevel="Level4" />
<Label Text="Paragraphs of text go here." />   

Alternatively, it can be set in C#:

Label label1 = new Label { Text = "Get started with .NET MAUI" };
Label label2 = new Label { Text = "Paragraphs of text go here." };
Label label3 = new Label { Text = "Installation" };
Label label4 = new Label { Text = "Paragraphs of text go here." };
Label label5 = new Label { Text = "Build your first app" };
Label label6 = new Label { Text = "Paragraphs of text go here." };
Label label7 = new Label { Text = "Publish your app" };
Label label8 = new Label { Text = "Paragraphs of text go here." };
SemanticProperties.SetHeadingLevel(label1, SemanticHeadingLevel.Level1);
SemanticProperties.SetHeadingLevel(label3, SemanticHeadingLevel.Level1);
SemanticProperties.SetHeadingLevel(label5, SemanticHeadingLevel.Level1);
SemanticProperties.SetHeadingLevel(label7, SemanticHeadingLevel.Level1);

In addition, the SetValue method can also be used to set the HeadingLevel attached property:

label1.SetValue(SemanticProperties.HeadingLevelProperty, SemanticHeadingLevel.Level1);

Semantic focus

Controls have a SetSemanticFocus extension method which forces screen reader focus to a specified element. For example, given a Label named label, screen reader focus can be forced to the element with the following code:

label.SetSemanticFocus();

Semantic screen reader

.NET MAUI provides the ISemanticScreenReader interface, with which you can instruct a screen reader to announce text to the user. The interface is exposed through the Default property, and is available in the Microsoft.Maui.Accessibility namespace.

To instruct a screen reader to announce text, use the Announce method, passing a string argument that represents the text. The following example demonstrates using this method:

SemanticScreenReader.Default.Announce("This is the announcement text.");

Limitations

The default platform screen reader must be enabled for text to be read aloud.

Automation properties

Automation properties are attached properties that can be added to any element to indicate how the element is reported to the underlying platform's accessibility framework.

The AutomationProperties class defines the following attached properties:

  • ExcludedWithChildren, of type bool?, determines if an element and its children should be excluded from the accessibility tree. For more information, see ExcludedWithChildren.
  • IsInAccessibleTree, of type bool?, indicates whether the element is available in the accessibility tree. For more information, see IsInAccessibleTree.
  • Name, of type string, represents a short description of the element that serves as a speakable identifier for that element. For more information, see Name.
  • HelpText, of type string, represents a longer description of the element, which can be thought of as tooltip text that's associated with the element. For more information, see HelpText.
  • LabeledBy, of type VisualElement, which enables another element to define accessibility information for the current element. For more information, see LabeledBy.

These attached properties set platform accessibility values so that a screen reader can speak about the element. For more information about attached properties, see Attached properties.

Different screen readers read different accessibility values. Therefore, when using automation properties it's recommended that thorough accessibility testing is carried out on each platform to ensure an optimal experience.

Important

Automation properties are the Xamarin.Forms approach to providing accessibility values in apps, and have been superseded by semantic properties. For more information about semantic properties, see Semantic properties.

ExcludedWithChildren

The ExcludedWithChildren attached property, of type bool?, determines if an element and its children should be excluded from the accessibility tree. This enables scenarios such as displaying an AbsoluteLayout over another layout such as a StackLayout, with the StackLayout being excluded from the accessibility tree when it's not visible. It can be used from XAML as follows:

<StackLayout AutomationProperties.ExcludedWithChildren="true">
...
</StackLayout>

Alternatively, it can be set in C# as follows:

StackLayout stackLayout = new StackLayout();
...
AutomationProperties.SetExcludedWithChildren(stackLayout, true);

When this attached property is set, .NET MAUI sets the IsInAccessibleTree attached property to false on the specified element and its children.

IsInAccessibleTree

Warning

This attached property should typically remain unset. The majority of controls should be present in the accessibility tree, and the AutomationProperties.ExcludedWithChildren attached property can be set in scenarios where an element and its children need removing from the accessibility tree.

The IsInAccessibleTree attached property, of type bool?, determines if the element is visible to screen readers. It must be set to true to use the other automation properties. This can be accomplished in XAML as follows:

<Entry AutomationProperties.IsInAccessibleTree="true" />

Alternatively, it can be set in C# as follows:

Entry entry = new Entry();
AutomationProperties.SetIsInAccessibleTree(entry, true);

Warning

On iOS, if the IsInAccessibleTree property is true on any control that has children the screen reader will be unable to reach the children. This is because iOS doesn't provide accessibility features that allow the navigation from a parent element into a child element.

Name

Important

The Name attached property has been deprecated in .NET 8. Instead, use the Description attached property.

The Name attached property value should be a short, descriptive text string that a screen reader uses to announce an element. This property should be set for elements that have a meaning that is important for understanding the content or interacting with the user interface. This can be accomplished in XAML as follows:

<ActivityIndicator AutomationProperties.IsInAccessibleTree="true"
                   AutomationProperties.Name="Progress indicator" />

Alternatively, it can be set in C# as follows:

ActivityIndicator activityIndicator = new ActivityIndicator();
AutomationProperties.SetIsInAccessibleTree(activityIndicator, true);
AutomationProperties.SetName(activityIndicator, "Progress indicator");

HelpText

Important

The HelpText attached property has been deprecated in .NET 8. Instead, use the Hint attached property.

The HelpText attached property should be set to text that describes the user interface element, and can be thought of as tooltip text associated with the element. This can be accomplished in XAML as follows:

<Button Text="Toggle ActivityIndicator"
        AutomationProperties.IsInAccessibleTree="true"
        AutomationProperties.HelpText="Tap to toggle the activity indicator" />

Alternatively, it can be set in C# as follows:

Button button = new Button { Text = "Toggle ActivityIndicator" };
AutomationProperties.SetIsInAccessibleTree(button, true);
AutomationProperties.SetHelpText(button, "Tap to toggle the activity indicator");

On some platforms, for edit controls such as an Entry, the HelpText property can sometimes be omitted and replaced with placeholder text. For example, "Enter your name here" is a good candidate for the Entry.Placeholder property that places the text in the control prior to the user's actual input.

LabeledBy

Important

The LabeledBy attached property has been deprecated in .NET 8. Instead, use a SemanticProperties.Description binding. For more information, see SemanticProperties: Description.

The LabeledBy attached property allows another element to define accessibility information for the current element. For example, a Label next to an Entry can be used to describe what the Entry represents. This can be accomplished in XAML as follows:

<Label x:Name="label" Text="Enter your name: " />
<Entry AutomationProperties.IsInAccessibleTree="true"
       AutomationProperties.LabeledBy="{x:Reference label}" />

Alternatively, it can be set in C# as follows:

Label label = new Label { Text = "Enter your name: " };
Entry entry = new Entry();
AutomationProperties.SetIsInAccessibleTree(entry, true);
AutomationProperties.SetLabeledBy(entry, label);

Important

The AutomationProperties.LabeledByProperty is not supported on iOS.

Testing accessibility

.NET MAUI apps typically target multiple platforms, which means testing the accessibility features according to the platform. Follow these links to learn how to test accessibility on each platform:

The following tools can assist with your accessibility testing:

However, none of these tools can perfectly emulate the screen reader user experience, and the best way to test and troubleshoot your apps for accessibility will always be manually on physical devices with screen readers.

Enabling screen readers

Each platform has a different default screen reader to narrate accessibility values:

  • Android has TalkBack. For information on enabling TalkBack, see Enable TalkBack.
  • iOS and macOS have VoiceOver. For information on enabling VoiceOver, see Enable VoiceOver.
  • Windows has Narrator. For information on enabling Narrator, see Enable Narrator.

Enable TalkBack

TalkBack is the primary screen reader used on Android. How it's enabled depends on the device manufacturer, Android version, and TalkBack version. However, TalkBack can typically be enabled on your Android device via the device settings:

  1. Open the Settings app.
  2. Select Accessibility > TalkBack.
  3. Turn Use TalkBack on.
  4. Select OK.

Note

While these steps apply to most devices, you might experience some differences.

A TalkBack tutorial opens automatically the first time you enable TalkBack.

For alternative methods of enabling TalkBack, see Turn Talkback on or off.

Enable VoiceOver

VoiceOver is the primary screen reader used on iOS and macOS. On iOS, VoiceOver can be enabled as follows:

  1. Open the Settings app.
  2. Select Accessibility > VoiceOver.
  3. Turn VoiceOver on.

A VoiceOver tutorial can be opened by selecting VoiceOver Practice, once VoiceOver is enabled.

For alternative methods of enabling VoiceOver, see Turn on and practice VoiceOver on iPhone and Turn on and practice VoiceOver on iPad.

On macOS, VoiceOver can be enabled as follows:

  1. Open the System Preferences.
  2. Select Accessibility > VoiceOver.
  3. Select Enable VoiceOver.
  4. Select Use VoiceOver.

A VoiceOver tutorial can be opened by selecting Open VoiceOver Training....

For alternative methods of enabling VoiceOver, see Turn VoiceOver on or off on Mac.

Enable Narrator

Narrator is the primary screen reader used on Windows. Narrator can be enabled by pressing the Windows logo key + Ctrl + Enter together. These keys can be pressed again to stop Narrator.

For more information about Narrator, see Complete guide to Narrator.

Accessibility checklist

Follow these tips to ensure that your .NET MAUI apps are accessible to the widest audience possible:

  • Ensure your app is perceivable, operable, understandable, and robust for all by following the Web Content Accessibility Guidelines (WCAG). WCAG is the global accessibility standard and legal benchmark for web and mobile. For more information, see Web Content Accessibility Guidelines (WCAG) Overview.
  • Make sure the user interface is self-describing. Test that all the elements of your user interface are screen reader accessible. Add descriptive text and hints when necessary.
  • Ensure that images and icons have alternate text descriptions.
  • Support large fonts and high contrast. Avoid hardcoding control dimensions, and instead prefer layouts that resize to accommodate larger font sizes. Test color schemes in high-contrast mode to ensure they are readable.
  • Design the visual tree with navigation in mind. Use appropriate layout controls so that navigating between controls using alternate input methods follows the same logical flow as using touch. In addition, exclude unnecessary elements from screen readers (for example, decorative images or labels for fields that are already accessible).
  • Don't rely on audio or color cues alone. Avoid situations where the sole indication of progress, completion, or some other state is a sound or color change. Either design the user interface to include clear visual cues, with sound and color for reinforcement only, or add specific accessibility indicators. When choosing colors, try to avoid a palette that is hard to distinguish for users with color blindness.
  • Provide captions for video content and a readable script for audio content. It's also helpful to provide controls that adjust the speed of audio or video content, and ensure that volume and transport controls are easy to find and use.
  • Localize your accessibility descriptions when the app supports multiple languages.
  • Test the accessibility features of your app on each platform it targets. For more information, see Testing accessibility.