react-native icon indicating copy to clipboard operation
react-native copied to clipboard

Adding TextInput prop accessibilityErrorMessage to announce with TalkBack/VoiceOver screenreaders

Open fabOnReact opened this issue 3 years ago • 46 comments

Summary

Android: The functionality consists of calling the AccessibilityNodeInfo#setError and #setContentInvalid method to display the error message in the TextInput. iOS: The accessibilityErrorMessage is stored in the accessibilityValue of the TextInput and it is announced with UIAccessibilityPostNotification. The acceptable parameters of accessibilityErrorMessage is a string. Setting accessibilityInvalid to true activates the error message. Setting accessibilityInvalid to false removes the error message.

Fixes #30848 - Adding an accessibilityErrorMessage prop to the TextInput Component: Android: The prop accessibilityErrorMessage triggers the AccessibilityNodeInfo method setError which automatically sets the correct properties on the AccessibilityNodeInfo that will inform screen readers of this state. The method calls setContentInvalid(true) and setError(youErrorString) on the AccessibilityNodeInfo. iOS: iOS has no standard pattern for the presentation of error states on text inputs. The message is saved in the accessibilityValue of the field.

Fixes #30859 - Detecting changes in the Error state (text inputs) Fabric - Android - Adding accessibilityErrorMessage to field AndroidTextInputState. ReactTextInputManager and ReactEditText receive state updates both from Javascript and cpp (fabric).

  • accessibilityErrorMessage is added to the fabric AndroidTextInputState field
  • The updates are received in the ReactAndroid API with method updateState from ReactTextInputManager
  • After updating the TextInput text with onChangeText, the update of the accessibilityErrorMessage is triggered with method maybeSetAccessibilityError which triggers setError.

More info:

Fabric - iOS - State Updates are triggered with RCTTextInputComponentView#updateProps. When the accessibilityErrorMessage or the text value of the TextInput changes, the accessibilityValue is set to that value and a VoiceOver announcement is triggered with UIAccessibilityPostNotification. Error announcements are triggered onChangeText with setAttributeString.

Paper - Android - Adding accessibilityErrorMessage to ReactTextInputShadowNode to trigger updates in Paper renderer when accessibilityErrorMessage is changed within the onChange callback.

Paper - iOS - To avoid duplicate screenreader announcement of the accessibilityError when typing, a screenreader announcement of the next typed character is triggered with RCTBaseTextInputView#setAttributedText if the error message is removed when accessibilityInvalid is true.

Related Links (Android):

Related Links (iOS):

Changelog

[General] [Added] - Adding TextInput prop accessibilityErrorMessage to announce with TalkBack/VoiceOver screenreaders

Test Plan

PR Branch - Android and iOS 24th June 87: iOS - Paper - accessibilityValue announces correctly with/out errorMessage set with onChangeText or with outside event (Paper) (link) 88: Android - accessibilityValue announces correctly with/out errorMessage set with onChangeText or with outside event (Fabric) (link) 89: iOS - accessibilityValue announces correctly with/out errorMessage set with onChangeText or with outside event (Fabric) (link)

PR Branch - Android 1. Test Cases of the functionality (Fabric) (link) 2. Test Cases of the functionality (Paper) (link)

PR Branch - iOS 73. Announcing error onChangeText and screenreader focus (Fabric) (link) 74. iOS - The screenreader announces the TextInput value after the errorMessage is cleared (link) 76. iOS - announce lastChar (not entire text) onChangeText and avoid multiple announcements (Fabric) (link) 77. iOS - announces or does not announce the accessibilityError through Button onPress (not onChangeText) (Fabric) (link) 78. iOS - the error is announced with accessibilityInvalid true and does not clear after typing text (onChangeText) (Fabric) (link)

Main Branch 6. Android - Runtime Error in main branch when passing value of 1 to TextInput placeholder prop (link) 70. iOS - Paper renderer does not update the accessibilityValue (link) 75. iOS - Exception thrown while executing UI block: - [RCTTextView setOnAccessibiltyAction:]: unrecognized selector sent to instance (Paper) (main branch) (link) 79. iOS - Exception thrown while executing UI block: - RCTUITextView setAccessibilityErrorMessage:]: unrecognized selector sent to instance (iOS - Paper on main branch) (link)

Issues Solved 7. TalkBack error does not clear error on the next typed character when using onChangeText (link) Other Tests 8. Setting the TextInput errorMessage state with setTextAndSelection Java API from JavaScript (link) 9. Setting the TextInput errorMessage state from fabric TextInput internal state to Java ReactTextUpdate API (link)

fabOnReact avatar Mar 23 '22 04:03 fabOnReact

Platform Engine Arch Size (bytes) Diff
ios - universal n/a --

Base commit: 25a25ea234fc60c7a0b99e9c70253f77a69edc60 Branch: main

analysis-bot avatar Mar 23 '22 04:03 analysis-bot

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 8,460,303 +1,669
android hermes armeabi-v7a 7,783,042 +1,147
android hermes x86 8,936,192 +1,657
android hermes x86_64 8,793,493 +1,869
android jsc arm64-v8a 9,093,774 +1,002
android jsc armeabi-v7a 8,291,352 +483
android jsc x86 9,144,575 +985
android jsc x86_64 9,403,650 +1,195

Base commit: 26b2bb5343f92672ed4e8f42c6f839e903124b06 Branch: main

analysis-bot avatar Mar 23 '22 05:03 analysis-bot

The documentation is included in PR https://github.com/facebook/react-native-website/pull/3010

fabOnReact avatar Apr 05 '22 08:04 fabOnReact

Documentation PR https://github.com/facebook/react-native-website/pull/3010

fabOnReact avatar Apr 11 '22 07:04 fabOnReact

Thanks, @kacieb. I'm currently working on iOS side of this functionality and I plan to complete it by Friday 6th of May.

fabOnReact avatar May 02 '22 11:05 fabOnReact

Thanks @blavalla. Once I complete the changes for code review Android: Role description is announced before the components text, rather than after #31042, I will further test the iOS functionality of the Issue Text input error for screenreaders #30848 and fix any issue in the iOS functionalities or think about potential improvements to the PR on the iOS side.

The PR summary includes a test case for iOS iOS - announcing error onChangeText and screenreader focus.

fabOnReact avatar May 25 '22 20:05 fabOnReact

@kacieb equivalent functionality in terms of web aria api https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-errormessage

necolas avatar Jun 04 '22 15:06 necolas

@kacieb equivalent functionality in terms of web aria api https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-errormessage

This is awesome @fabriziobertoglio1987! Would it be possible to follow the aria names and pattern for the JavaScript API? No native changes would be needed, you can do all of this in JavaScript I think. So instead of:

The acceptable parameters are null or a string. The parameter null removes the error message.

It would be something like

The acceptable parameters of accessibilityErrorMessage is a string. Setting accessibilityInvalid to true activates the error message. Setting accessibilityInvalid to false removes the error message.

Instead of checking for null on the error message to clear it, you'd check the accessibilityInvalid boolean for when to set or clear the message.

Does that make sense? Please let me know if I can help explain better!

cc @necolas

kacieb avatar Jun 06 '22 17:06 kacieb

something to note is that the value of aria-errormessage is meant to be the id of an element that contains the error message.

necolas avatar Jun 06 '22 18:06 necolas

something to note is that the value of aria-errormessage is meant to be the id of an element that contains the error message.

Good note. I think this is out of scope for this PR. Definitely something we can improve in the future.

kacieb avatar Jun 07 '22 12:06 kacieb

  • [x] fix regression in Fabric iOS. Reintroduce solution from commits https://github.com/facebook/react-native/pull/33468/commits/318a96420f0593dc59c030193009e9cba31eb666 https://github.com/facebook/react-native/pull/33468/commits/99b39d5e344463ee9ca2f4528e203411da02b9ee
  • [x] fix regression - the error message is cleared when screenreader focus is moved out of the textinput
  • [x] extensive iOS and Android tests
  • [x] review diff and PR summary
  • [x] update test cases video recording

fabOnReact avatar Jun 23 '22 01:06 fabOnReact

This looks good to me on the JS side! I'll work with blavalla to make sure we can land safely. cc @lunaleaps for awareness.

kacieb avatar Jun 27 '22 15:06 kacieb

@blavalla has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

facebook-github-bot avatar Aug 03 '22 23:08 facebook-github-bot

@fabriziobertoglio1987 Do we have accompanying API documentation on the website for this?

lunaleaps avatar Aug 10 '22 23:08 lunaleaps

Thanks for this great feature!

Related… when this gets landed, it would be great to also submit a PR to @types/react-native to add the new prop(s).

yungsters avatar Aug 11 '22 21:08 yungsters

Thanks. I agree @blavalla https://github.com/facebook/react-native/pull/33468#pullrequestreview-1061123093. I added some comments and links with this commit https://github.com/facebook/react-native/pull/33468/commits/d85c90ad3fd80a408343cd3924e0af1ef0963713.

fabOnReact avatar Aug 12 '22 06:08 fabOnReact

@fabriziobertoglio1987 Do we have accompanying API documentation on the website for this?

@lunaleaps This is the PR https://github.com/facebook/react-native-website/pull/3010 for the documentation. Thanks

fabOnReact avatar Aug 12 '22 07:08 fabOnReact

Related… when this gets landed, it would be great to also submit a PR to @types/react-native to add the new prop(s).

@yungsters I published PR https://github.com/DefinitelyTyped/DefinitelyTyped/pull/61748. Thanks a lot.

fabOnReact avatar Aug 12 '22 07:08 fabOnReact

App crashing after trying to parse accessibilityErrorMessage prop raw value (rebase 14th Oct.)

The issue was solved after rebasing again on 17th Oct, including this for documentation purposes.

The app crashed at RawProps.cpp:92 with error:

function at: assertion failed (parser_ && "The object is not parsed. `parse` must be called before `at`.")' 

https://www.icloud.com/iclouddrive/0e4zx_DEQrjC6s2uDVLTLXYPQ#null_pointer_dereference

The issue would not reproduce after removing the changes to the attributedstring ParagraphAttributes field accessibilityErrorMessage, but the error message is not displayed onChangeText.

The error initially seems triggered by conversions fromRawValue, RawProps, convertRawProp. The error could be caused by a conversion issue in ParagraphAttributes[accessibilityErrorMessage] and an error in parsing the value.

The fix consisted in:

  • rebase again (diff from 14th Oct at 09:00 and 17th Oct 13:22 Rome)
  • clean build (which is not the cause of the issue as I tried it several times)
crash with log

https://user-images.githubusercontent.com/24992535/196162666-62c12b88-2ba1-4f15-bcc8-31918ecc3e5c.mp4

after rebasing and clean build

https://user-images.githubusercontent.com/24992535/196162657-8dda9513-aa96-4de4-b661-97d9c126f39a.mp4

fabOnReact avatar Oct 17 '22 11:10 fabOnReact

  • [x] add fabric .cpp configurations https://github.com/fabriziobertoglio1987/react-native/commit/110b191b14e3cb692bb6a33f0f129b4f0215f9a6

fabOnReact avatar Nov 01 '22 20:11 fabOnReact

@fabriziobertoglio1987 Is this ready to be reviewed again?

lunaleaps avatar Nov 04 '22 21:11 lunaleaps

Fabric Android - trigger the error onChangeText

https://user-images.githubusercontent.com/24992535/200121108-de546f2f-2238-44d9-a028-a69fe05183bc.mp4

fabOnReact avatar Nov 05 '22 13:11 fabOnReact

Fabric Android - trigger the error with a button (outside of onChangeText callback)

https://user-images.githubusercontent.com/24992535/200121219-1189d00f-bb44-46e2-941b-43740b3792f5.mp4

fabOnReact avatar Nov 05 '22 13:11 fabOnReact

Fabric Android - announce error after changing text value

https://user-images.githubusercontent.com/24992535/200121367-e4ce5324-ef2a-48d2-b391-c56d28d9ee94.mp4

fabOnReact avatar Nov 05 '22 13:11 fabOnReact

Paper Android - setting accessibilityError onChangeText

https://user-images.githubusercontent.com/24992535/200121527-26a193cb-a85c-466d-8df1-7c23abea3a82.mp4

fabOnReact avatar Nov 05 '22 13:11 fabOnReact

PR build artifact for b1b8bf0d1d9c5ab51fa5f0d65670a5b22c83f799 is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 05 '22 13:11 pull-bot

PR build artifact for b1b8bf0d1d9c5ab51fa5f0d65670a5b22c83f799 is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 05 '22 13:11 pull-bot

PR build artifact for f0d0186ebad7312cdcd54b74d8d47e47bd4d741b is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 05 '22 14:11 pull-bot

PR build artifact for f0d0186ebad7312cdcd54b74d8d47e47bd4d741b is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 05 '22 14:11 pull-bot

Fabric iOS - triggering accessibilityErrorMessage onChangeText

https://user-images.githubusercontent.com/24992535/200287750-44973c43-59e2-4268-8ee4-9916b53330f5.mp4

fabOnReact avatar Nov 07 '22 10:11 fabOnReact