Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compose iOS accessibility support #75

Merged
merged 13 commits into from
Feb 28, 2024
5 changes: 4 additions & 1 deletion mpd.tree
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@
<toc-element toc-title="Why Compose Multiplatform" href="https://www.jetbrains.com/lp/compose-multiplatform/"/>
<toc-element id="compose-images-resources.md"/>
<toc-element id="compose-navigation-routing.md"/>
<toc-element id="compose-ios-ui-integration.md" toc-title="Integration with other UI frameworks"/>
<toc-element toc-title="iOS specific features">
zamulla marked this conversation as resolved.
Show resolved Hide resolved
<toc-element id="compose-ios-ui-integration.md" toc-title="Integration with UIKit and SwiftUI"/>
<toc-element id="compose-ios-accessibility.md" toc-title="iOS accessibility support"/>
</toc-element>
<toc-element id="compose-android-only-components.md"/>
<toc-element toc-title="Compose Multiplatform for web" href="https://kotlinlang.org/docs/wasm-get-started.html"/>
<toc-element id="compose-compatibility-and-versioning.md"/>
Expand Down
106 changes: 106 additions & 0 deletions topics/compose/compose-ios-accessibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
[//]: # (title: Support for iOS accessibility features)

Compose Multiplatform accessibility support for iOS allows people with disabilities to interact with Compose Multiplatform UI
zamulla marked this conversation as resolved.
Show resolved Hide resolved
as comfortably as with native UIs:
zamulla marked this conversation as resolved.
Show resolved Hide resolved
* Screen readers and VoiceOver can access the content of the Compose Multiplatform UI.
* Compose Multiplatform UI supports the same gestures as the native UIs for navigation and interaction.
zamulla marked this conversation as resolved.
Show resolved Hide resolved

This is possible because semantics data produced by Compose APIs is now mapped to native objects and properties
that are consumed by iOS Accessibility Services. For most interfaces built with Material widgets, this should happen
automatically.

You can also use this semantic data in testing and other automation: properties such as `testTag` will correctly map
to native accessibility properties such as `accessibilityIdentifier`. This makes semantic data from Compose Multiplatform available
to Accessibility Services and XCTest framework.

Notable limitations of the current accessibility support:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here you can move the repetitive part to the list's intro:

The Compose accessibility API doesn't currently cover(support):

  • Live regions, announcements about..
  • UIKit elements inside Compose Multiplatform UI.

* Live regions (announcements about content changes in a specific area) are not supported yet.
* [UIKit elements inside Compose Multiplatform UI](compose-ios-ui-integration.md#use-uikit-inside-compose-multiplatform)
are not currently covered by the Compose accessibility API.

iOS accessibility support is in the early stages of development. If you have trouble with this feature,
we would appreciate your feedback in the [#compose-ios](https://kotlinlang.slack.com/archives/C0346LWVBJ4/p1678888063176359)
Slack channel, or as an issue in the [Compose Multiplatform GitHub repo](https://github.com/JetBrains/compose-multiplatform/issues).
zamulla marked this conversation as resolved.
Show resolved Hide resolved

## Customize accessibility tree synchronization

By default, the iOS accessibility tree is synchronized with the UI only when Accessibility Services are running;
by default, no accessibility logs are written.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "accessibility logs part" doesn't seem to be relevant to the tree synchronization section. If you remove it, there wouldn't be the "by default" repetition

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API allows both to control the sync behavior and logging of the synchronization events, so more of a the fact that logging doesn't seem to be relevant is a bigger problem :)

I rephrased for clarity.

You can customize this behavior, for example, when you want to debug events and interactions:
activate the option to always synchronize the accessibility tree, so that the tree is rewritten every time the UI updates.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sentence is quite long, maybe split it after the colon?


> Always synchronizing the tree can be quite useful for debugging and testing, but be aware that there is a significant
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A part of the second sentence repeats the section's intro, I think we can safely shorten this tip to:

Constant synchronizing (or Constant synchronization of) the tree can be quite useful for debugging and testing but can degrade your app's performance.

Also, it look likes rather important, maybe turn it into a note?

> overhead associated with this. Synchronizing the tree with the UI regardless of Accessibility Services can degrade
> the performance of your app.
>
> {type="tip"}

Compose Multiplatform [provides APIs](#accessibility-apis) to configure the tree sync behavior:
modify the `accessibilitySyncOptions` parameter inside the `configure` block of a `ComposeUIViewController` call:
zamulla marked this conversation as resolved.
Show resolved Hide resolved

```kotlin
ComposeUIViewController(configure = {
accessibilitySyncOptions = AccessibilitySyncOptions.Always(object: AccessibilityDebugLogger {
override fun log(message: Any?) {
if (message == null) {
println()
} else {
println("[a11y]: $message")
}
}
})
}) {
// your @Composable content
}
```

## Accessibility APIs

The following APIs provided by Compose Multiplatform help you customize iOS accessibility behavior.
zamulla marked this conversation as resolved.
Show resolved Hide resolved

### AccessibilityDebugLogger

The `AccessibilityDebugLogger` interface contains the logging function to be used for debugging:

```kotlin
// package androidx.compose.ui.platform

@ExperimentalComposeApi
interface AccessibilityDebugLogger {

// Logs the message to the debug logger, or null as a separator of log blobs
fun log(message: Any?)
}
```

### AccessibilitySyncOptions

The `AccessibilitySyncOptions` class contains available options for synchronizing the accessibility tree:

```kotlin
// package androidx.compose.ui.platform

@ExperimentalComposeApi
sealed class AccessibilitySyncOptions {

// Option to never synchronize the accessibility tree
object Never: AccessibilitySyncOptions

// Option to synchronize the tree only when Accessibility Services are running
//
// You can include an AccessibilityDebugLogger to log interactions and tree syncing events
class WhenRequiredByAccessibilityServices(debugLogger: AccessibilityDebugLogger?)

// Option to always synchronize the accessibility tree
//
// You can include an AccessibilityDebugLogger to log interactions and tree syncing events
class Always(debugLogger: AccessibilityDebugLogger?)
}
```

## What's next?
danil-pavlov marked this conversation as resolved.
Show resolved Hide resolved

Try out the project generated by [the Kotlin Multiplatform wizard](https://kmp.jetbrains.com/) in your usual iOS accessibility workflow.

Compose Multiplatform also supports [recourse qualifiers](compose-images-resources.md) that will be helpful when adapting
a UI to a particular situation.