diff --git a/change/react-native-windows-fix-scrollview-programmatic.json b/change/react-native-windows-fix-scrollview-programmatic.json new file mode 100644 index 00000000000..005a38d17ef --- /dev/null +++ b/change/react-native-windows-fix-scrollview-programmatic.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Honor programmatic scrollTo when scrollEnabled=false (gestures remain blocked), matching iOS/Android semantics", + "packageName": "react-native-windows", + "email": "collindanielschneide@gmail.com", + "dependentChangeType": "patch" +} diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp index 2e9905ed190..65aecb43d64 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp @@ -1179,10 +1179,13 @@ void ScrollViewComponentView::HandleCommand(const winrt::Microsoft::ReactNative: } void ScrollViewComponentView::scrollTo(winrt::Windows::Foundation::Numerics::float3 offset, bool animate) noexcept { - if (!std::static_pointer_cast(viewProps())->scrollEnabled) { - return; - } - + // scrollEnabled={false} must only disable *user* scroll gestures, matching + // iOS and Android where setContentOffset / scrollToOffset still work when + // scrolling is disabled. Programmatic scrolls - the scrollTo command, and + // scrollToIndex / scrollToOffset which route through it - previously hit a + // scrollEnabled early-return here and were silently dropped. User-gesture input + // is gated separately (m_scrollVisual.ScrollEnabled, set from scrollEnabled in + // updateProps), so it is safe to always honor a programmatic scroll here. m_scrollVisual.TryUpdatePosition(offset, animate); }