diff --git a/change/react-native-windows-82bcd92e-18b7-42d0-b6f0-dc428b565d5d.json b/change/react-native-windows-82bcd92e-18b7-42d0-b6f0-dc428b565d5d.json new file mode 100644 index 00000000000..96c1bac678b --- /dev/null +++ b/change/react-native-windows-82bcd92e-18b7-42d0-b6f0-dc428b565d5d.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "[Fabric] Implementation of accessibilityDescription", + "packageName": "react-native-windows", + "email": "kvineeth@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/@react-native-windows/tester/src/js/examples-win/Accessibility/AccessibilityExampleWindows.tsx b/packages/@react-native-windows/tester/src/js/examples-win/Accessibility/AccessibilityExampleWindows.tsx index 96283b4a38c..0848d282dc3 100644 --- a/packages/@react-native-windows/tester/src/js/examples-win/Accessibility/AccessibilityExampleWindows.tsx +++ b/packages/@react-native-windows/tester/src/js/examples-win/Accessibility/AccessibilityExampleWindows.tsx @@ -28,6 +28,7 @@ class AccessibilityBaseExample extends React.Component { accessibilityLevel={1} accessibilityItemType="comment" accessibilityAccessKey="accessKey" + accessibilityDescription="Sample Description" accessibilityAnnotation={{ typeID: 'Comment', typeName: 'Check Comment', diff --git a/packages/e2e-test-app-fabric/test/__snapshots__/AccessibilityTest.test.ts.snap b/packages/e2e-test-app-fabric/test/__snapshots__/AccessibilityTest.test.ts.snap index 000d77c4e41..49efe6f3d60 100644 --- a/packages/e2e-test-app-fabric/test/__snapshots__/AccessibilityTest.test.ts.snap +++ b/packages/e2e-test-app-fabric/test/__snapshots__/AccessibilityTest.test.ts.snap @@ -39,6 +39,7 @@ exports[`Accessibility Tests Accessibility data for Label,Level and Hint 1`] = ` "AnnotationPattern.TypeName": "Check Comment", "AutomationId": "accessibility-base-view-1", "ControlType": 50026, + "Description": "Sample Description", "HelpText": "A hint for the blue box.", "ItemType": "comment", "Level": 1, diff --git a/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap b/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap index 305681c7e5a..bcfdefaedf8 100644 --- a/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap +++ b/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap @@ -17,6 +17,7 @@ exports[`snapshotAllPages Accessibility Windows 1`] = ` "typeName": "Check Comment", } } + accessibilityDescription="Sample Description" accessibilityHint="A hint for the blue box." accessibilityItemType="comment" accessibilityLabel="A blue box" diff --git a/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric/RNTesterApp-Fabric.cpp b/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric/RNTesterApp-Fabric.cpp index 5231892bbe1..4b64dfe33cc 100644 --- a/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric/RNTesterApp-Fabric.cpp +++ b/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric/RNTesterApp-Fabric.cpp @@ -525,6 +525,7 @@ winrt::Windows::Data::Json::JsonObject DumpUIATreeRecurse( BSTR itemStatus; BSTR itemType; BSTR accessKey; + BSTR description = nullptr; pTarget->get_CurrentAutomationId(&automationId); pTarget->get_CurrentControlType(&controlType); @@ -545,6 +546,11 @@ winrt::Windows::Data::Json::JsonObject DumpUIATreeRecurse( pTarget4->get_CurrentLevel(&level); pTarget4->Release(); } + IUIAutomationElement6 *pTarget6; + hr = pTarget->QueryInterface(__uuidof(IUIAutomationElement6), reinterpret_cast(&pTarget6)); + if (SUCCEEDED(hr) && pTarget6) { + pTarget6->get_CurrentFullDescription(&description); + } result.Insert(L"AutomationId", winrt::Windows::Data::Json::JsonValue::CreateStringValue(automationId)); result.Insert(L"ControlType", winrt::Windows::Data::Json::JsonValue::CreateNumberValue(controlType)); InsertStringValueIfNotEmpty(result, L"HelpText", helpText); @@ -560,6 +566,7 @@ winrt::Windows::Data::Json::JsonObject DumpUIATreeRecurse( InsertStringValueIfNotEmpty(result, L"ItemStatus", itemStatus); InsertStringValueIfNotEmpty(result, L"ItemType", itemType); InsertStringValueIfNotEmpty(result, L"AccessKey", accessKey); + InsertStringValueIfNotEmpty(result, L"Description", description); DumpUIAPatternInfo(pTarget, result); IUIAutomationElement *pChild; @@ -580,6 +587,9 @@ winrt::Windows::Data::Json::JsonObject DumpUIATreeRecurse( ::SysFreeString(localizedControlType); ::SysFreeString(name); ::SysFreeString(itemStatus); + ::SysFreeString(itemType); + ::SysFreeString(accessKey); + ::SysFreeString(description); return result; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp index b40c83eabe7..34a666b9cb7 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp @@ -588,6 +588,12 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPropertyValue(PROPERT pRetVal->bstrVal = SysAllocString(itemtype.c_str()); break; } + case UIA_FullDescriptionPropertyId: { + pRetVal->vt = VT_BSTR; + auto desc = ::Microsoft::Common::Unicode::Utf8ToUtf16(props->accessibilityDescription.value_or("")); + pRetVal->bstrVal = SysAllocString(desc.c_str()); + break; + } } return hr; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp index f23ddcda0ff..4beb0e82f58 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp @@ -819,6 +819,12 @@ void ComponentView::updateAccessibilityProps( oldViewProps.accessibilityItemType, newViewProps.accessibilityItemType); + winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty( + EnsureUiaProvider(), + UIA_FullDescriptionPropertyId, + oldViewProps.accessibilityDescription, + newViewProps.accessibilityDescription); + if ((oldViewProps.accessibilityState.has_value() && oldViewProps.accessibilityState->selected.has_value()) != ((newViewProps.accessibilityState.has_value() && newViewProps.accessibilityState->selected.has_value()))) { auto compProvider = diff --git a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp index 00b3a0afb17..ff5b778be44 100644 --- a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp @@ -56,6 +56,14 @@ HostPlatformViewProps::HostPlatformViewProps( ReactNativeFeatureFlags::enableCppPropsIteratorSetter() ? sourceProps.accessibilityAccessKey : convertRawProp(context, rawProps, "accessibilityAccessKey", sourceProps.accessibilityAccessKey, {})), + accessibilityDescription( + ReactNativeFeatureFlags::enableCppPropsIteratorSetter() ? sourceProps.accessibilityDescription + : convertRawProp( + context, + rawProps, + "accessibilityDescription", + sourceProps.accessibilityDescription, + {})), accessibilityLiveRegion( ReactNativeFeatureFlags::enableCppPropsIteratorSetter() ? sourceProps.accessibilityLiveRegion : convertRawProp( @@ -104,6 +112,7 @@ void HostPlatformViewProps::setProp( RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLevel); RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityItemType); RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityAccessKey); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityDescription); RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLiveRegion); RAW_SET_PROP_SWITCH_CASE_BASIC(keyDownEvents); RAW_SET_PROP_SWITCH_CASE_BASIC(keyUpEvents); diff --git a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h index e1afe3f9683..3466a06dde6 100644 --- a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h +++ b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h @@ -32,6 +32,7 @@ class HostPlatformViewProps : public BaseViewProps { std::optional accessibilityAnnotation{}; std::optional accessibilityItemType{}; std::optional accessibilityAccessKey{}; + std::optional accessibilityDescription{}; // std::optional overflowAnchor{}; std::optional tooltip{}; diff --git a/vnext/src-win/Libraries/Components/View/View.windows.js b/vnext/src-win/Libraries/Components/View/View.windows.js index abb8fc96211..5865e1f2908 100644 --- a/vnext/src-win/Libraries/Components/View/View.windows.js +++ b/vnext/src-win/Libraries/Components/View/View.windows.js @@ -67,6 +67,7 @@ const View: component( accessibilityLabel, accessibilityLabelledBy, accessibilityLevel, // Windows + accessibilityDescription, //Windows accessibilityLiveRegion, accessibilityPosInSet, // Windows accessibilitySetSize, // Windows @@ -78,6 +79,7 @@ const View: component( 'aria-expanded': ariaExpanded, 'aria-multiselectable': ariaMultiselectable, // Windows 'aria-required': ariaRequired, // Windows + 'aria-description': ariaDescription, //Windows 'aria-hidden': ariaHidden, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, @@ -250,6 +252,7 @@ const View: component( } accessibilityLabel={ariaLabel ?? accessibilityLabel} accessibilityLevel={ariaLevel ?? accessibilityLevel} + accessibilityDescription={ariaDescription ?? accessibilityDescription} accessibilityPosInSet={ariaPosinset ?? accessibilityPosInSet} accessibilitySetSize={ariaSetsize ?? accessibilitySetSize} focusable={_focusable} @@ -303,6 +306,9 @@ const View: component( } accessibilityLabel={ariaLabel ?? accessibilityLabel} accessibilityLevel={ariaLevel ?? accessibilityLevel} + accessibilityDescription={ + ariaDescription ?? accessibilityDescription + } accessibilityPosInSet={ariaPosinset ?? accessibilityPosInSet} accessibilitySetSize={ariaSetsize ?? accessibilitySetSize} focusable={_focusable} diff --git a/vnext/src-win/Libraries/Components/View/ViewAccessibility.d.ts b/vnext/src-win/Libraries/Components/View/ViewAccessibility.d.ts index 14d93975846..7b48156b751 100644 --- a/vnext/src-win/Libraries/Components/View/ViewAccessibility.d.ts +++ b/vnext/src-win/Libraries/Components/View/ViewAccessibility.d.ts @@ -315,6 +315,14 @@ export interface AccessibilityPropsWindows { * Access keys are used in keyboard navigation to allow quick navigation to UI in an application. */ accessibilityAccessKey?: string; //Windows + + /** + * accessibilityDescription provides more detailed information specific to the element (i.e. last edit date, full location for a file) + * while accessibilityHint provides information on what will happen when they perform an action. + * + */ + accessibilityDescription?: string; // Windows + 'aria-description'?: string; // Windows } export interface AccessibilityPropsAndroid { diff --git a/vnext/src-win/Libraries/Components/View/ViewPropTypes.windows.js b/vnext/src-win/Libraries/Components/View/ViewPropTypes.windows.js index b5fc28d6c25..29debb4cd42 100644 --- a/vnext/src-win/Libraries/Components/View/ViewPropTypes.windows.js +++ b/vnext/src-win/Libraries/Components/View/ViewPropTypes.windows.js @@ -454,6 +454,8 @@ type ViewPropsWindows = $ReadOnly<{| 'aria-posinset'?: ?number, accessibilitySetSize?: ?number, 'aria-setsize'?: ?number, + accessibilityDescription?: ?string, + 'aria-description'?: ?string, /** * Specifies if the control should show System focus visuals diff --git a/vnext/src-win/Libraries/NativeComponent/BaseViewConfig.windows.js b/vnext/src-win/Libraries/NativeComponent/BaseViewConfig.windows.js index 6f6e08784ed..4fef13aacff 100644 --- a/vnext/src-win/Libraries/NativeComponent/BaseViewConfig.windows.js +++ b/vnext/src-win/Libraries/NativeComponent/BaseViewConfig.windows.js @@ -385,6 +385,7 @@ const validAttributesForNonEventProps = { accessibilityAnnotation: true, // [Windows] accessibilityItemType: true, // [Windows] accessibilityAccessKey: true, // [Windows] + accessibilityDescription: true, // [Windows] disabled: true, // [Windows] focusable: true, // [Windows] keyDownEvents: true, // [Windows]