Skip to content

Commit bbf9a13

Browse files
authored
fix: preventing Talkback erroneously focusing valid icon and adding similar support for MobileCombobox (#8435)
* preventing talkback from focusing valid icon and adding to mobile combobox * update string, match some logic from #8329
1 parent 94445e8 commit bbf9a13

File tree

3 files changed

+18
-16
lines changed

3 files changed

+18
-16
lines changed

packages/@react-spectrum/combobox/intl/en-US.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@
22
"loading": "Loading...",
33
"noResults": "No results",
44
"clear": "Clear",
5-
"invalid": "(invalid)"
5+
"invalid": "(invalid)",
6+
"valid": "(valid)"
7+
68
}

packages/@react-spectrum/combobox/src/MobileComboBox.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,10 @@ export const ComboBoxButton = React.forwardRef(function ComboBoxButton(props: Co
179179
let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/combobox');
180180
let valueId = useId();
181181
let invalidId = useId();
182+
let validId = useId();
182183
let validationIcon = validationState === 'invalid'
183184
? <AlertMedium id={invalidId} aria-label={stringFormatter.format('invalid')} />
184-
: <CheckmarkMedium />;
185+
: <CheckmarkMedium id={validId} aria-label={stringFormatter.format('valid')} />;
185186

186187
let validation = React.cloneElement(validationIcon, {
187188
UNSAFE_className: classNames(
@@ -202,7 +203,8 @@ export const ComboBoxButton = React.forwardRef(function ComboBoxButton(props: Co
202203
props['aria-labelledby'],
203204
props['aria-label'] && !props['aria-labelledby'] ? props.id : null,
204205
valueId,
205-
validationState === 'invalid' ? invalidId : null
206+
validationState === 'invalid' ? invalidId : null,
207+
validationState === 'valid' ? validId : null
206208
].filter(Boolean).join(' '),
207209
elementType: 'div'
208210
}, objRef);

packages/@react-spectrum/textfield/src/TextFieldBase.tsx

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export const TextFieldBase = forwardRef(function TextFieldBase(props: TextFieldB
9898
let validId = useId();
9999
let validationIcon = isInvalid
100100
? <AlertMedium />
101-
: <CheckmarkMedium id={validId} aria-label={stringFormatter.format('valid')} />;
101+
: <CheckmarkMedium id={validId} aria-hidden aria-label={stringFormatter.format('valid')} />;
102102
let validation = cloneElement(validationIcon, {
103103
UNSAFE_className: classNames(
104104
styles,
@@ -107,6 +107,15 @@ export const TextFieldBase = forwardRef(function TextFieldBase(props: TextFieldB
107107
)
108108
});
109109

110+
// Add validation icon IDREF to aria-describedby when validationState is valid
111+
let inputPropsAriaDescribedBy = inputProps['aria-describedby'];
112+
if (
113+
!isInvalid && validationState === 'valid' && !isLoading && !isDisabled &&
114+
(!inputPropsAriaDescribedBy || !inputPropsAriaDescribedBy.includes(validId))
115+
) {
116+
inputProps['aria-describedby'] = [inputPropsAriaDescribedBy, validId].join(' ').trim();
117+
}
118+
110119
let {focusProps, isFocusVisible} = useFocusRing({
111120
isTextInput: true,
112121
autoFocus
@@ -129,18 +138,7 @@ export const TextFieldBase = forwardRef(function TextFieldBase(props: TextFieldB
129138
)
130139
}>
131140
<ElementType
132-
{...mergeProps(
133-
inputProps,
134-
hoverProps,
135-
focusProps,
136-
validationState === 'valid' && !isLoading && !isDisabled
137-
? {
138-
'aria-describedby': inputProps['aria-describedby']
139-
? `${inputProps['aria-describedby']} ${validId}`
140-
: validId
141-
}
142-
: undefined
143-
)}
141+
{...mergeProps(inputProps, hoverProps, focusProps)}
144142
ref={inputRef as any}
145143
rows={multiLine ? 1 : undefined}
146144
className={

0 commit comments

Comments
 (0)