From d1beae952e5437e8f8de8d2eff3fc90fe2d856e4 Mon Sep 17 00:00:00 2001 From: Protik Biswas Date: Mon, 2 Feb 2026 14:20:14 +0530 Subject: [PATCH 1/3] adding fix for shadow in rounded box --- .../CompositionSwitcher.idl | 9 ++- .../Composition/CompositionContextHelper.cpp | 15 ++++ .../CompositionViewComponentView.cpp | 81 ++++++++++++++++++- 3 files changed, 103 insertions(+), 2 deletions(-) diff --git a/vnext/Microsoft.ReactNative/CompositionSwitcher.idl b/vnext/Microsoft.ReactNative/CompositionSwitcher.idl index a0946aacd98..1896b0dc357 100644 --- a/vnext/Microsoft.ReactNative/CompositionSwitcher.idl +++ b/vnext/Microsoft.ReactNative/CompositionSwitcher.idl @@ -45,9 +45,16 @@ enum SnapPointsAlignment { void Opacity(Single value); void BlurRadius(Single value); void Color(Windows.UI.Color value); + void Mask(IBrush mask); + void SourcePolicy(CompositionDropShadowSourcePolicy policy); } - [webhosthidden][experimental] interface IVisual { +[webhosthidden][experimental] enum CompositionDropShadowSourcePolicy { + Default = 0, + InheritedOnly = 1 +}; + +[webhosthidden][experimental] interface IVisual { void InsertAt(IVisual visual, Int32 index); void Remove(IVisual visual); IVisual GetAt(UInt32 index); diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp index 7a38f5df942..aa410c86bab 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp @@ -50,6 +50,7 @@ struct CompositionTypeTraits { using CompositionStretch = winrt::Windows::UI::Composition::CompositionStretch; using CompositionStrokeCap = winrt::Windows::UI::Composition::CompositionStrokeCap; using CompositionSurfaceBrush = winrt::Windows::UI::Composition::CompositionSurfaceBrush; + using CompositionDropShadowSourcePolicy = winrt::Windows::UI::Composition::CompositionDropShadowSourcePolicy; using Compositor = winrt::Windows::UI::Composition::Compositor; using ContainerVisual = winrt::Windows::UI::Composition::ContainerVisual; using CubicBezierEasingFunction = winrt::Windows::UI::Composition::CubicBezierEasingFunction; @@ -122,6 +123,7 @@ struct CompositionTypeTraits { using CompositionStretch = winrt::Microsoft::UI::Composition::CompositionStretch; using CompositionStrokeCap = winrt::Microsoft::UI::Composition::CompositionStrokeCap; using CompositionSurfaceBrush = winrt::Microsoft::UI::Composition::CompositionSurfaceBrush; + using CompositionDropShadowSourcePolicy = winrt::Microsoft::UI::Composition::CompositionDropShadowSourcePolicy; using Compositor = winrt::Microsoft::UI::Composition::Compositor; using ContainerVisual = winrt::Microsoft::UI::Composition::ContainerVisual; using CubicBezierEasingFunction = winrt::Microsoft::UI::Composition::CubicBezierEasingFunction; @@ -218,6 +220,19 @@ struct CompDropShadow : public winrt::implements< m_shadow.Color(color); } + void Mask(winrt::Microsoft::ReactNative::Composition::Experimental::IBrush const &mask) noexcept { + if (mask) { + m_shadow.Mask(mask.as()->InnerBrush()); + } else { + m_shadow.Mask(nullptr); + } + } + + void SourcePolicy( + winrt::Microsoft::ReactNative::Composition::Experimental::CompositionDropShadowSourcePolicy policy) noexcept { + m_shadow.SourcePolicy(static_cast(policy)); + } + private: typename TTypeRedirects::DropShadow m_shadow; }; diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp index 5f50d14da18..015c164fb84 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp @@ -708,7 +708,86 @@ void ComponentView::applyShadowProps(const facebook::react::ViewProps &viewProps shadow.Color(theme()->Color(*viewProps.shadowColor)); } - Visual().as().Shadow(shadow); + // Check if any border radius is set + auto borderMetrics = BorderPrimitive::resolveAndAlignBorderMetrics(m_layoutMetrics, viewProps); + bool hasBorderRadius = borderMetrics.borderRadii.topLeft.horizontal != 0 || + borderMetrics.borderRadii.topRight.horizontal != 0 || borderMetrics.borderRadii.bottomLeft.horizontal != 0 || + borderMetrics.borderRadii.bottomRight.horizontal != 0 || borderMetrics.borderRadii.topLeft.vertical != 0 || + borderMetrics.borderRadii.topRight.vertical != 0 || borderMetrics.borderRadii.bottomLeft.vertical != 0 || + borderMetrics.borderRadii.bottomRight.vertical != 0; + + if (hasBorderRadius) { + // When borderRadius is set, we need to create a shadow mask that follows the rounded rectangle shape. + // Use CompositionVisualSurface to capture the clipped visual's appearance as the shadow mask. + bool maskSet = false; + + // Try Microsoft (WinUI3) Composition first + auto msCompositor = + winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerCompositor( + m_compContext); + if (msCompositor) { + auto innerVisual = + winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerVisual( + Visual()); + if (innerVisual) { + // Create a VisualSurface that captures the visual (with its clip applied) + auto visualSurface = msCompositor.CreateVisualSurface(); + visualSurface.SourceVisual(innerVisual); + visualSurface.SourceSize( + {m_layoutMetrics.frame.size.width * m_layoutMetrics.pointScaleFactor, + m_layoutMetrics.frame.size.height * m_layoutMetrics.pointScaleFactor}); + + // Create a brush from the visual surface to use as shadow mask + auto maskBrush = msCompositor.CreateSurfaceBrush(visualSurface); + maskBrush.Stretch(winrt::Microsoft::UI::Composition::CompositionStretch::Fill); + + // Get the inner shadow and set the mask + auto innerShadow = winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper:: + InnerDropShadow(shadow); + if (innerShadow) { + innerShadow.Mask(maskBrush); + maskSet = true; + } + } + } + + // Fallback to System (Windows.UI) Composition if Microsoft Composition is not available + if (!maskSet) { + auto sysCompositor = + winrt::Microsoft::ReactNative::Composition::Experimental::SystemCompositionContextHelper::InnerCompositor( + m_compContext); + if (sysCompositor) { + auto innerVisual = + winrt::Microsoft::ReactNative::Composition::Experimental::SystemCompositionContextHelper::InnerVisual( + Visual()); + if (innerVisual) { + auto visualSurface = sysCompositor.CreateVisualSurface(); + visualSurface.SourceVisual(innerVisual); + visualSurface.SourceSize( + {m_layoutMetrics.frame.size.width * m_layoutMetrics.pointScaleFactor, + m_layoutMetrics.frame.size.height * m_layoutMetrics.pointScaleFactor}); + + auto maskBrush = sysCompositor.CreateSurfaceBrush(visualSurface); + maskBrush.Stretch(winrt::Windows::UI::Composition::CompositionStretch::Fill); + + auto innerShadow = + winrt::Microsoft::ReactNative::Composition::Experimental::SystemCompositionContextHelper::InnerDropShadow( + shadow); + if (innerShadow) { + innerShadow.Mask(maskBrush); + } + } + } + } + + // Apply shadow to OuterVisual (which is not clipped) so the shadow can extend beyond the clip + OuterVisual().as().Shadow(shadow); + Visual().as().Shadow(nullptr); + } else { + // No border radius - apply shadow directly to Visual (original behavior) + Visual().as().Shadow(shadow); + OuterVisual().as().Shadow(nullptr); + } } void ComponentView::updateTransformProps( From 30146804f46fec5d2c5e2afc7db4922a5b6f440b Mon Sep 17 00:00:00 2001 From: Protik Biswas Date: Mon, 2 Feb 2026 14:23:31 +0530 Subject: [PATCH 2/3] Change files --- ...ative-windows-7ee31594-04e3-459a-8d85-f305644d691c.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/react-native-windows-7ee31594-04e3-459a-8d85-f305644d691c.json diff --git a/change/react-native-windows-7ee31594-04e3-459a-8d85-f305644d691c.json b/change/react-native-windows-7ee31594-04e3-459a-8d85-f305644d691c.json new file mode 100644 index 00000000000..0ca87450b2c --- /dev/null +++ b/change/react-native-windows-7ee31594-04e3-459a-8d85-f305644d691c.json @@ -0,0 +1,7 @@ +{ + "comment": "adding fix for shadow in rounded box", + "type": "prerelease", + "packageName": "react-native-windows", + "email": "protikbiswas@microsoft.com", + "dependentChangeType": "patch" +} From 3e9c5dd9f2f7f4cd5841d2b3063b839ff944e194 Mon Sep 17 00:00:00 2001 From: Protik Biswas Date: Tue, 3 Feb 2026 09:46:46 +0530 Subject: [PATCH 3/3] Skip Xaml WinUI3 component in e2e visitAllPages test --- packages/e2e-test-app-fabric/test/visitAllPages.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/e2e-test-app-fabric/test/visitAllPages.test.ts b/packages/e2e-test-app-fabric/test/visitAllPages.test.ts index 01c855a2a45..a6b80275d0a 100644 --- a/packages/e2e-test-app-fabric/test/visitAllPages.test.ts +++ b/packages/e2e-test-app-fabric/test/visitAllPages.test.ts @@ -47,6 +47,7 @@ describe('visitAllPages', () => { if ( component === 'Flyout' || component === 'XAML' || + component === 'Xaml WinUI3 (Experimental, for Fabric)' || component === 'SwipeableCard' ) { console.log('Skipping: ' + component);