Skip to content

Conversation

@Nitin-100
Copy link
Contributor

@Nitin-100 Nitin-100 commented Jan 21, 2026

Description

This PR fixes Issue #15557 - "Pop-ups of Xaml controls need positioning and dismissal"

When XAML controls with popups (like ComboBox, DatePicker, TimePicker) are hosted inside a React Native ScrollView via ContentIslandComponentView, two bugs occur:

  1. Bug 1 (Position): After scrolling, opening the popup shows it at the wrong position (offset by the scroll amount)
  2. Bug 2 (Light Dismiss): Opening a popup and then scrolling leaves the popup floating at its original position instead of dismissing

Root Cause Analysis

Bug 1: Popup Position

  • ContentIslandComponentView uses ChildSiteLink.LocalToParentTransformMatrix for popup positioning
  • Issue 1: getClientRect() returns values in physical pixels (scaled by pointScaleFactor), but LocalToParentTransformMatrix expects logical pixels (DIPs)
  • Issue 2: Transform was updated asynchronously via UIDispatcher().Post(), causing race conditions where popup opened with stale transform values
  • Issue 3: Initial transform wasn't set before Connect(), causing wrong position even without scrolling

Bug 2: Light Dismiss on Scroll

  • XAML's native light dismiss behavior wasn't being triggered when scroll begins in React Native

Solution

Bug 1 Fix: Popup Position After Scroll

  1. Convert to DIPs: Divide getClientRect() values by pointScaleFactor before setting LocalToParentTransformMatrix
  2. Synchronous updates: Remove async UIDispatcher().Post() wrapper - update transform immediately
  3. Initial transform: Set LocalToParentTransformMatrix in OnMounted() before Connect()
  4. Scroll notification: ScrollViewComponentView fires LayoutMetricsChanged event when scroll position changes

Bug 2 Fix: Light Dismiss on Scroll

  • Added DismissPopupsRequest event to ContentIslandComponentView
  • When scroll begins, ScrollViewComponentView recursively finds all ContentIslandComponentView children and fires FireDismissPopupsRequest()
  • 3rd party XAML components subscribe to this event and dismiss their own popups
  • Core remains XAML-agnostic - no XAML-specific code in the framework

Files Changed

Core Fix (vnext/Microsoft.ReactNative/)

  • Fabric/Composition/ContentIslandComponentView.cpp - DIP conversion, sync updates, DismissPopupsRequest event
  • Fabric/Composition/ScrollViewComponentView.cpp - Fire LayoutMetricsChanged on scroll, dismiss popups on scroll begin

Testing

  1. Run the XamlPopupRepro sample in Playground
  2. Scroll down in the ScrollView
  3. Click a ComboBox to open dropdown - should appear at correct position (right at the button)
  4. Open a ComboBox dropdown, then scroll - dropdown should close automatically

##Screenshot

testingFix.mp4

…#15557)

- Add SetXamlRoot() API on ContentIslandComponentView for 3rd party XAML components
- Add DismissPopups() using VisualTreeHelper.GetOpenPopupsForXamlRoot()
- Fire LayoutMetricsChanged on scroll to update popup positions
- Dismiss child ContentIsland popups when scroll begins
- Add ComboBox sample component demonstrating the pattern
- Add xamlPopupBug test sample for playground-composition
@Nitin-100 Nitin-100 requested review from a team as code owners January 21, 2026 07:49
Copy link
Contributor

@sundaramramaswamy sundaramramaswamy left a comment

Choose a reason for hiding this comment

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

Please address comments.

@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs: Author Feedback The issue/PR needs activity from its author (label drives bot activity) label Jan 23, 2026
…#15557)

- Set LocalToParentTransformMatrix synchronously before Connect() to fix initial position
- Fire LayoutMetricsChanged on scroll to update position after scrolling
- Add DismissPopupsRequest event for 3P components to implement light dismiss
- Update ComboBox sample to use event-based approach (core remains XAML-agnostic)
@microsoft-github-policy-service microsoft-github-policy-service bot removed the Needs: Author Feedback The issue/PR needs activity from its author (label drives bot activity) label Jan 25, 2026
Nitin Chaudhary and others added 3 commits January 25, 2026 19:08
Issue microsoft#15557: Fix popup positioning for XAML controls in ScrollView

Bug 1 (Position Fix):
- Convert getClientRect() physical pixels to DIPs by dividing by pointScaleFactor
- LocalToParentTransformMatrix expects logical pixels (DIPs), not physical pixels
- Update transform synchronously instead of async to avoid race conditions
- Set initial transform in OnMounted() before Connect()

Bug 2 (Light Dismiss Fix):
- Add DismissPopupsRequest event for 3P components to handle popup dismissal
- ScrollView fires event when scroll begins via DismissChildContentIslandPopups()
- Core remains XAML-agnostic - 3P components handle their own popups
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pop-ups of Xaml controls need positioning and dismissal

2 participants