From 3b272ba80d47c528c18f4ca5be0751df784ec23e Mon Sep 17 00:00:00 2001 From: Collin Date: Sat, 11 Jul 2026 11:58:11 +0800 Subject: [PATCH 1/2] fix(textinput): correct placeholder layout size and default font size Two defects in the native placeholder path of WindowsTextInputComponentView: 1. CreatePlaceholderLayout() built LayoutConstraints (which are in DIPs) from m_imgWidth/m_imgHeight, which are *physical* pixels (frame * pointScaleFactor). The placeholder was therefore laid out in a box pointScaleFactor x too large and rendered at a different height than the typed text at display scales > 100%. Convert the constraint back to DIPs. 2. The NaN-fontSize guard computed `TextAttributes::defaultTextAttributes().fontSize;` as a discarded expression (missing assignment), so a placeholder with no explicit fontSize kept NaN instead of the default. Assign it to textAttributes.fontSize. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../TextInput/WindowsTextInputComponentView.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp index 2fd8fcde9a1..d9e4393685d 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp @@ -1690,7 +1690,7 @@ winrt::com_ptr<::IDWriteTextLayout> WindowsTextInputComponentView::CreatePlaceho const auto &props = windowsTextInputProps(); facebook::react::TextAttributes textAttributes = props.textAttributes; if (std::isnan(props.textAttributes.fontSize)) { - facebook::react::TextAttributes::defaultTextAttributes().fontSize; + textAttributes.fontSize = facebook::react::TextAttributes::defaultTextAttributes().fontSize; } textAttributes.fontSizeMultiplier = m_fontSizeMultiplier; fragment1.string = props.placeholder; @@ -1698,8 +1698,13 @@ winrt::com_ptr<::IDWriteTextLayout> WindowsTextInputComponentView::CreatePlaceho attributedString.appendFragment(std::move(fragment1)); facebook::react::LayoutConstraints constraints; - constraints.maximumSize.width = static_cast(m_imgWidth); - constraints.maximumSize.height = static_cast(m_imgHeight); + // m_imgWidth/m_imgHeight are physical pixels (frame * pointScaleFactor), but + // LayoutConstraints are expressed in DIPs. Feeding physical px laid the + // placeholder out in a box pointScaleFactor x too large, so the placeholder was + // measured/positioned at a different height than the typed text. Convert to DIPs. + const float scale = m_layoutMetrics.pointScaleFactor != 0.0f ? m_layoutMetrics.pointScaleFactor : 1.0f; + constraints.maximumSize.width = static_cast(m_imgWidth) / scale; + constraints.maximumSize.height = static_cast(m_imgHeight) / scale; facebook::react::WindowsTextLayoutManager::GetTextLayout( facebook::react::AttributedStringBox(attributedString), {} /*TODO*/, constraints, textLayout); From 883bea2feebbee21c1ca1767e31b1d45374ddb43 Mon Sep 17 00:00:00 2001 From: Collin Date: Sat, 11 Jul 2026 16:42:38 +0800 Subject: [PATCH 2/2] Change files --- change/react-native-windows-fix-textinput-placeholder.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/react-native-windows-fix-textinput-placeholder.json diff --git a/change/react-native-windows-fix-textinput-placeholder.json b/change/react-native-windows-fix-textinput-placeholder.json new file mode 100644 index 00000000000..b759d12c2d5 --- /dev/null +++ b/change/react-native-windows-fix-textinput-placeholder.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Fix placeholder layout constraints fed physical px instead of DIPs; fix no-op NaN fontSize guard in CreatePlaceholderLayout", + "packageName": "react-native-windows", + "email": "collindanielschneide@gmail.com", + "dependentChangeType": "patch" +}