Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions src/components/FormHelpMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ function FormHelpMessage({
const icons = useMemoizedLazyExpensifyIcons(['DotIndicator', 'Exclamation']);
const isWeb = getPlatform() === CONST.PLATFORM.WEB;
const shouldAnnounceError = isError && typeof message === 'string' && !!message && !shouldRenderMessageAsHTML && children == null;
const shouldUseSeparateWebLiveAnnouncement = isWeb && !!nativeID && shouldAnnounceError;
const visibleMessageRole = shouldUseSeparateWebLiveAnnouncement || !shouldAnnounceError ? undefined : CONST.ROLE.ALERT;
const visibleMessageLiveRegion = shouldUseSeparateWebLiveAnnouncement || !shouldAnnounceError ? undefined : 'assertive';

const HTMLMessage = useMemo(() => {
if (typeof message !== 'string' || !shouldRenderMessageAsHTML) {
Expand All @@ -78,10 +81,7 @@ function FormHelpMessage({
}

return (
<View
style={[styles.flexRow, styles.alignItemsCenter, styles.mt2, styles.mb1, style]}
nativeID={nativeID}
>
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2, styles.mb1, style]}>
{isError && shouldShowRedDotIndicator && (
<View
accessible
Expand Down Expand Up @@ -109,15 +109,27 @@ function FormHelpMessage({
) : (
<Text
style={[isError ? styles.formError : styles.formHelp, styles.mb0]}
role={shouldAnnounceError ? CONST.ROLE.ALERT : undefined}
nativeID={nativeID}
role={visibleMessageRole}
// TalkBack on some Android versions skips role-only alert announcements,
// so keep native accessibilityRole/live-region as a platform fallback.
accessibilityRole={!isWeb && shouldAnnounceError ? CONST.ROLE.ALERT : undefined}
accessibilityLiveRegion={shouldAnnounceError ? 'assertive' : undefined}
accessibilityLiveRegion={visibleMessageLiveRegion}
>
{message}
</Text>
))}
{shouldUseSeparateWebLiveAnnouncement && (
// Keep a separate live region for immediate web announcements without
// changing the visible described text Safari relies on when refocusing inputs.
<Text
style={styles.hiddenElementOutsideOfWindow}
role={CONST.ROLE.ALERT}
accessibilityLiveRegion="assertive"
>
{message}
</Text>
)}
</View>
</View>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,8 @@ function BaseTextInput({
// This is workaround for https://github.com/Expensify/App/issues/47939: in case when user is using Chrome on Android we set inputMode to 'search' to disable autocomplete bar above the keyboard.
// If we need some other inputMode (eg. 'decimal'), then the autocomplete bar will show, but we can do nothing about it as it's a known Chrome bug.
const inputMode = inputProps.inputMode ?? (isMobileChrome() ? 'search' : undefined);
const accessibilityLabel = [label, hint, errorText ? translate('common.yourReviewIsRequired') : ''].filter(Boolean).join(', ');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this intended to remove the common.yourReviewIsRequired message?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I did not restore the generic phrase because the final fix uses the actual error text on web, while native error announcement remains unchanged through the native implementation.

const helpMessageTextID = `${helpMessageId}-text`;
const accessibilityLabel = [label, hint, errorText].filter(Boolean).join(', ');
const loadingSpinnerReasonAttributes: SkeletonSpanReasonAttributes = {
context: 'BaseTextInput.isLoading',
isLoading: !!inputProps.isLoading,
Expand Down Expand Up @@ -496,7 +497,8 @@ function BaseTextInput({
markdownStyle={markdownStyle}
accessibilityLabel={inputProps.accessibilityLabel ?? accessibilityLabel}
keyboardType={inputProps.keyboardType}
aria-describedby={inputHelpText ? helpMessageId : undefined}
aria-describedby={inputHelpText ? helpMessageTextID : undefined}
aria-invalid={errorText ? true : undefined}
/>
{!!suffixCharacter && (
<View style={[styles.textInputSuffixWrapper, suffixContainerStyle]}>
Expand Down Expand Up @@ -570,7 +572,7 @@ function BaseTextInput({
</PressableWithoutFeedback>
{!!inputHelpText && (
<FormHelpMessage
nativeID={helpMessageId}
nativeID={helpMessageTextID}
isError={!!errorText}
message={inputHelpText}
/>
Expand Down
Loading