# Get started with screen reader support

> Use the screen reader support APIs to make your first accessible button.

The screen reader support APIs are agnostic of the UI system, so they work with UI Toolkit, uGUI, custom UI frameworks, and non-UI content such as 2D or 3D objects in the game world. For simplicity, this guide uses UI Toolkit, but you can adapt the code to your UI framework of choice.

## Example overview

This example illustrates how to create an accessibility node, connect it to a UI Toolkit button, and test it with platform screen readers. By the end, you'll have a button that native screen readers can read and activate.

## Prerequisites

This guide is for developers familiar with the Unity Editor, UI Toolkit, and C# scripting. Before you start, get familiar with the following:

* [UI Toolkit](/engine/6000.7/manual/uitoolkits/uielements.md)
* [Screen readers](/engine/6000.7/manual/accessibility/concepts/screen-readers-intro.md)
* [Accessibility module](ScriptRef:UnityEngine.AccessibilityModule)

## Enable the Accessibility module

The [Accessibility module](ScriptRef:UnityEngine.AccessibilityModule) is enabled by default. If for some reason it's not enabled in your project, do the following to enable it:

1. Select **Window** > **Package Management** > **Package Manager** to open the **Package Manager**.
2. Select the **Built-in** section.
3. Select the **Accessibility** module.
4. Select **Enable**.

## Create the button

Use UI Toolkit to create a **Start Game** button in your scene.

1. Create a project with any template.

2. Create a UXML file named `AccessibleStartMenu.uxml` with the following content:

   ```xml
   <ui:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
       <ui:Button text="Start Game" name="startButton"/>
   </ui:UXML>

   ```

3. Create a C# script named `AccessibleStartMenu.cs` with the following content:

```cs
using UnityEngine;
    using UnityEngine.UIElements;

    public class AccessibleStartMenu : MonoBehaviour
    {
        Button m_Button;

        void OnEnable()
        {
            VisualElement root = GetComponent<UIDocument>().rootVisualElement;
            m_Button = root.Q<Button>("startButton");

            m_Button.clicked += OnButtonClicked;
        }

        void OnDisable()
        {
            m_Button.clicked -= OnButtonClicked;
        }

        void OnButtonClicked()
        {
            Debug.Log("Start Game button clicked");
        }
    }
```

## Create the accessibility hierarchy

The accessibility hierarchy is a semantic representation of your UI that screen readers use to discover and interact with your content. Screen readers cannot detect `GameObject` components or UI elements directly. They rely on this hierarchy to navigate your application. You create an [`AccessibilityHierarchy`](/engine/6000.7/script-reference/unityengine/accessibility/accessibilityhierarchy.md), then add an [`AccessibilityNode`](/engine/6000.7/script-reference/unityengine/accessibility/accessibilitynode.md) that represents the **Start Game** button.

To create the accessibility hierarchy:

1. Add the `UnityEngine.Accessibility` namespace.
2. Create an [`AccessibilityHierarchy`](/engine/6000.7/script-reference/unityengine/accessibility/accessibilityhierarchy.md) instance.
3. Create and add an [`AccessibilityNode`](/engine/6000.7/script-reference/unityengine/accessibility/accessibilitynode.md) to the accessibility hierarchy.
4. Set the [`label`](/engine/6000.7/script-reference/unityengine/accessibility/accessibilitynode/label.md), [`role`](/engine/6000.7/script-reference/unityengine/accessibility/accessibilitynode/role.md), and [`state`](/engine/6000.7/script-reference/unityengine/accessibility/accessibilitynode/state.md) properties of the node according to the button's text and interactable state.

```lang-cs
// ...
using UnityEngine.Accessibility;

public class AccessibleStartMenu : MonoBehaviour
{
    // ...

    AccessibilityHierarchy m_AccessibilityHierarchy;
    AccessibilityNode m_AccessibilityNode;

    void OnEnable()
    {
        // ...

        CreateAccessibilityHierarchy();
    }

    // ...

    void CreateAccessibilityHierarchy()
    {
        // Create a new accessibility hierarchy.
        m_AccessibilityHierarchy = new AccessibilityHierarchy();

        // Create a new accessibility node with the button's text as the label
        // (what the screen readers announces).
        m_AccessibilityNode = m_AccessibilityHierarchy.AddNode(m_Button.text);

        // Set a semantic role (tells the screen reader this is a button).
        m_AccessibilityNode.role = AccessibilityRole.Button;

        // Set the state (is it currently interactable?).
        m_AccessibilityNode.state = m_Button.enabledSelf ?
            AccessibilityState.None : AccessibilityState.Disabled;
    }
}
```

## Set the node's screen coordinates according to the button's size and position

To set the node's screen coordinates:

1. Track the button's changes in size and position.
2. Calculate its screen coordinates from its world coordinates and the UI scale factor.
3. Set the node's [`frame`](/engine/6000.7/script-reference/unityengine/accessibility/accessibilitynode/frame.md) property to the calculated screen rectangle.

Update the `AccessibleStartMenu.cs` script as below:

```lang-cs
public class AccessibleStartMenu : MonoBehaviour
{
    // ...

    void OnEnable()
    {
        // ...

        m_Button.RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);
    }

    void OnDisable()
    {
        // ...

        m_Button.UnregisterCallback<GeometryChangedEvent>(OnGeometryChanged);
    }

    // ...

    void OnGeometryChanged(GeometryChangedEvent evt)
    {
        Rect worldRect = m_Button.worldBound;
        float scale = m_Button.panel.scaledPixelsPerPoint;

        // Update the screen coordinates of the node.
        m_AccessibilityNode.frame =
            new Rect(worldRect.position * scale, worldRect.size * scale);
    }
}
```

## Connect the node's activation event to the button

Subscribe to the node's [`invoked`](/engine/6000.7/script-reference/unityengine/accessibility/accessibilitynode/invoked.md) event, which is triggered when the user activates the node via the screen reader, then invoke the button's [`NavigationSubmitEvent`](/engine/6000.7/script-reference/unityengine/uielements/navigationsubmitevent.md) in the event handler.

Update the `CreateAccessibilityHierarchy` method in the `AccessibleStartMenu.cs` script as below:

```lang-cs
public class AccessibleStartMenu : MonoBehaviour
{
    // ...

    void CreateAccessibilityHierarchy()
    {
        // ...

        // Handle when the user activates this node (e.g., double-tap).
        // Called `selected` in versions before Unity 6.3.
        m_AccessibilityNode.invoked += () =>
        {
            using var evt = NavigationSubmitEvent.GetPooled();
            evt.target = m_Button;
            m_Button.SendEvent(evt);

            return true;
        };
    }
}
```

## Activate the accessibility hierarchy when a screen reader is enabled

1. When the menu appears, activate the accessibility hierarchy by assigning it to [`AssistiveSupport.activeHierarchy`](/engine/6000.7/script-reference/unityengine/accessibility/assistivesupport/activehierarchy.md).
   * When the user turns the screen reader off, `AssistiveSupport.activeHierarchy` is automatically set to `null` to free resources.
2. Re-assign the hierarchy every time the user turns the screen reader on.
3. When the menu disappears, remove the hierarchy by setting `AssistiveSupport.activeHierarchy` to `null`.

```lang-cs
public class AccessibleStartMenu : MonoBehaviour
{
    // ...

    void OnEnable()
    {
        // ...

        AssistiveSupport.activeHierarchy = m_AccessibilityHierarchy;
        AssistiveSupport.screenReaderStatusChanged += OnScreenReaderStatusChanged;
    }

    void OnDisable()
    {
        // ...

        AssistiveSupport.activeHierarchy = null;
        AssistiveSupport.screenReaderStatusChanged -= OnScreenReaderStatusChanged;
    }

    // ...

    void OnScreenReaderStatusChanged(bool enabled)
    {
        if (enabled)
        {
            AssistiveSupport.activeHierarchy = m_AccessibilityHierarchy;
        }
        // else
        // {
        //     // This is automatically done when the user turns the screen
        //     // reader off.
        //     AssistiveSupport.activeHierarchy = null;
        // }
    }
}
```

You created a semantic representation ([`AccessibilityNode`](/engine/6000.7/script-reference/unityengine/accessibility/accessibilitynode.md)) of the visual button that screen readers can discover and interact with.

The complete `AccessibleStartMenu.cs` script is as follows:

```cs
using UnityEngine;
using UnityEngine.Accessibility;
using UnityEngine.UIElements;

public class AccessibleStartMenu : MonoBehaviour
{
    Button m_Button;

    AccessibilityHierarchy m_AccessibilityHierarchy;
    AccessibilityNode m_AccessibilityNode;

    void OnEnable()
    {
        VisualElement root = GetComponent<UIDocument>().rootVisualElement;
        m_Button = root.Q<Button>("startButton");

        m_Button.clicked += OnButtonClicked;
        m_Button.RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);

        CreateAccessibilityHierarchy();

        AssistiveSupport.activeHierarchy = m_AccessibilityHierarchy;
        AssistiveSupport.screenReaderStatusChanged += OnScreenReaderStatusChanged;
    }

    void OnDisable()
    {
        m_Button.clicked -= OnButtonClicked;
        m_Button.UnregisterCallback<GeometryChangedEvent>(OnGeometryChanged);

        AssistiveSupport.activeHierarchy = null;
        AssistiveSupport.screenReaderStatusChanged -= OnScreenReaderStatusChanged;
    }

    void CreateAccessibilityHierarchy()
    {
        // Create a new accessibility hierarchy.
        m_AccessibilityHierarchy = new AccessibilityHierarchy();

        // Create a new accessibility node with the button's text as the label
        // (what the screen readers announces).
        m_AccessibilityNode = m_AccessibilityHierarchy.AddNode(m_Button.text);

        // Set a semantic role (tells the screen reader this is a button).
        m_AccessibilityNode.role = AccessibilityRole.Button;

        // Set the state (is it currently interactable?).
        m_AccessibilityNode.state = m_Button.enabledSelf ?
            AccessibilityState.None : AccessibilityState.Disabled;

        // Handle when the user activates this node (e.g., double-tap).
        // Called `selected` in versions before Unity 6.3.
        m_AccessibilityNode.invoked += () =>
        {
            using var evt = NavigationSubmitEvent.GetPooled();
            evt.target = m_Button;
            m_Button.SendEvent(evt);

            return true;
        };
    }

    void OnGeometryChanged(GeometryChangedEvent evt)
    {
        Rect worldRect = m_Button.worldBound;
        float scale = m_Button.panel.scaledPixelsPerPoint;

        // Update the screen coordinates of the node.
        m_AccessibilityNode.frame =
            new Rect(worldRect.position * scale, worldRect.size * scale);
    }

    void OnButtonClicked()
    {
        Debug.Log("Start Game button clicked");
    }

    void OnScreenReaderStatusChanged(bool isEnabled)
    {
        if (isEnabled)
        {
            AssistiveSupport.activeHierarchy = m_AccessibilityHierarchy;
        }
        // else
        // {
        //     // This is automatically done when the user turns the screen
        //     // reader off.
        //     AssistiveSupport.activeHierarchy = null;
        // }
    }
}

```

## Attach the script

To attach the script to your scene:

1. Create an empty `GameObject` in your scene and name it `AccessibleStartMenu`.
2. Add a `UI Document` component to the `GameObject`.
3. Create a Panel Settings Asset and assign it to the `Panel Settings` field in the Inspector window of the `UI Document` component.
4. Assign the `AccessibleStartMenu.uxml` file to the `Source Asset` field.
5. Add the `AccessibleStartMenu.cs` script to the `GameObject`.

## Test the hierarchy and node properties in Play mode

To test the hierarchy and node properties in the Unity Editor:

1. Enter Play mode.
2. Select **Window** > **Accessibility** > **Hierarchy Viewer**.
3. Verify that the accessibility hierarchy shows the accessibility node with the correct properties.


**The Accessibility Hierarchy Viewer displaying the properties of the accessibility node representing the "Start Game" button:**
![](/api/media?file=/engine/6000.7/media/images/a11y-hierarchy-viewer-get-started.png)

## Test the screen reader interaction on your target platform

To test screen reader interaction on your target platform:

1. Build and run the application on your target platform (Android, iOS, Windows, or macOS).

2. Get familiar with the gestures or commands of your platform's built-in screen reader:

   * **Android**: [TalkBack gestures on Android](https://support.google.com/accessibility/android/answer/6151827)
   * **iOS**: [VoiceOver gestures on iPhone](https://support.apple.com/en-us/guide/iphone/iph3e2e2281/ios)
   * **Windows**: [Narrator commands on Windows](https://support.microsoft.com/en-us/windows/chapter-2-narrator-basics-5ff4591e-7b6d-245e-c95d-ce83c0a1a8d4)
   * **macOS**: [VoiceOver commands on Mac](https://support.apple.com/en-us/guide/voiceover/vo14111/mac)

3. Enable the screen reader.

4. Navigate to the button using screen reader gestures or commands. The screen reader should be able to focus on the button and announce "Start Game, button".

5. Activate the button using the screen reader's activation gesture or command. The button should respond, and the text "Start Game button clicked" should appear in the [player log](/engine/6000.7/manual/scripting/debugging-and-diagnostics/log-files.md).

## Additional resources

* 📚 **Documentation**: [Accessibility module API reference](ScriptRef:UnityEngine.AccessibilityModule)
* 📺 **Video**: [Reach new audiences with Accessibility and Localization in Unity 6 (Unite 2025)](https://youtu.be/Ezz7R--kf6c?si=gnPx8uJTcgCF02an)
* ⚙️ **Sample project**: [LetterSpell: example of an accessible Unity application](https://github.com/Unity-Technologies/a11y-public-sample)
* 👥 **Community**: [Unity Discussions: Accessibility](https://discussions.unity.com/tag/Accessibility-Features)
