Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Single-line TextInput text is drawn below center and clipped on ARM64 (New Architecture)

Đang mở
#16,481 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 2 ngày

@ryfow đang làm issue này rồi.

Từ ngày 12/10/2026.

  • #16482 của @ryfow — đang mở

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
35/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Đình trệ
Công nghệ
cpp, react-native
Lĩnh vực
frontend

Hướng nghiên cứu

The issue identifies WindowsTextInputComponentView::GetContentSize() as the source of the incorrect height, in the New Architecture Windows text input component. First inspect its TxGetNaturalSize extent and the linked pull request #16482. Done means ARM64 reports a sensible content size and single-line text and placeholders are vertically centered without clipping; verify the multiline onContentSizeChange result too.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

bug Needs: Triage :mag:
Problem Description

On the New Architecture (Fabric) on ARM64, a single-line TextInput that is taller than its text draws the text and placeholder starting at the vertical middle of the box, not centered in it. The top half of the input is empty, and in shorter inputs the bottom of the text is clipped.

This comes from #15754 ("Center single line textinputs"), which centers single-line text using the height returned by WindowsTextInputComponentView::GetContentSize(). On ARM64 that height is always about 0, so the centering offset becomes half the box height.

Root cause: GetContentSize() calls ITextServices::TxGetNaturalSize with this extent:

SIZE extentHimetric = {
    static_cast<LONG>(availableWidth * scale * HIMETRIC_PER_INCH / dpi),
    static_cast<LONG>(std::numeric_limits<LONG>::max() * HIMETRIC_PER_INCH / dpi)};

psizelExtent is the extent used for zooming the control, not a layout constraint. A very large positive height therefore scales the returned natural size down to about 0. I measured this in a 40px-tall input with fontSize: 18 at 96 DPI (ARM64):

extentHimetric.cy passed natural size returned (px)
LONG_MAX scaled (saturates to 2147483647) (2, 0)
1000000 (2, 0)
frame height (1058) (3, 1)
-1 (74, 24) (correct)

With contentHeight = 0, calculateContentVerticalOffset() computes (40 - 0) / 2 = 20 px, so the 24px-tall text is drawn from y=20 to y=44 in a 40px box.

Steps To Reproduce
  1. Create an app with the New Architecture cpp-app template:

    npx @react-native-community/[email protected] init RnwRepro --version 0.81.5
    cd RnwRepro
    npm install [email protected]
    npx @react-native-community/cli init-windows --template cpp-app --overwrite
    
  2. Replace App.tsx with the code below. Each input is tinted so you can compare its box with where its text is drawn.

  3. On an ARM64 Windows device, run npx react-native run-windows --arch ARM64.

  4. Compare the text in inputs 1–5 and 7 with their tinted boxes, and read the contentSize line under input 6.

import React, { useEffect, useState } from 'react';
import { PixelRatio, StyleSheet, Text, TextInput, View } from 'react-native';

// Each TextInput is tinted so a screenshot shows its box against where its text is drawn.
// Single-line text should be vertically centered in its box.
const App = () => {
  const [measured, setMeasured] = useState('type in the multiline box');
  // Case 7 gets its text from JS after mount, so the native side sees a text change.
  const [late, setLate] = useState('');
  useEffect(() => {
    const timer = setTimeout(() => setLate('Set from JS Hg'), 2000);
    return () => clearTimeout(timer);
  }, []);

  return (
    <View style={styles.screen}>
      <Text style={styles.info}>
        PixelRatio {PixelRatio.get()} · fontScale {PixelRatio.getFontScale()}
      </Text>

      <Text style={styles.label}>1. Height 40, fontSize 18, placeholder</Text>
      <TextInput style={[styles.input, styles.h40]} placeholder="Placeholder Hg" />

      <Text style={styles.label}>2. Height 40, fontSize 18, value</Text>
      <TextInput style={[styles.input, styles.h40]} defaultValue="Value Hg" />

      <Text style={styles.label}>3. Height 80, fontSize 18, value</Text>
      <TextInput style={[styles.input, styles.h80]} defaultValue="Value Hg" />

      <Text style={styles.label}>4. Default height, fontSize 18, value</Text>
      <TextInput style={styles.input} defaultValue="Value Hg" />

      <Text style={styles.label}>5. Default height and font, value</Text>
      <TextInput style={styles.tint} defaultValue="Value Hg" />

      <Text style={styles.label}>
        6. Multiline, fontSize 18: onContentSizeChange reports GetContentSize()
      </Text>
      <TextInput
        multiline
        style={[styles.input, styles.h80]}
        defaultValue="Value Hg"
        onContentSizeChange={(e) => {
          const { width, height } = e.nativeEvent.contentSize;
          const text = `contentSize ${width.toFixed(1)} x ${height.toFixed(1)}`;
          console.log(text);
          setMeasured(text);
        }}
      />
      <Text style={styles.info}>{measured}</Text>

      <Text style={styles.label}>7. Height 40, fontSize 18, value set from JS after 2 s</Text>
      <TextInput style={[styles.input, styles.h40]} value={late} placeholder="Waiting" onChangeText={setLate} />
    </View>
  );
};

const styles = StyleSheet.create({
  screen: { flex: 1, padding: 16, backgroundColor: 'white' },
  info: { fontSize: 14, marginVertical: 4 },
  label: { fontSize: 12, marginTop: 12, marginBottom: 2, color: '#555' },
  tint: { backgroundColor: 'rgba(255,0,0,0.25)' },
  input: { backgroundColor: 'rgba(255,0,0,0.25)', fontSize: 18 },
  h40: { height: 40 },
  h80: { height: 80 },
});

export default App;
Expected Results

Text and placeholder in each single-line TextInput are vertically centered in the tinted box, as intended by #15754.

Actual Results

In each single-line input, the top of the text sits at the vertical middle of the box. In the 40px inputs (1, 2, 7) the descenders are cut off. In the default-height inputs (4, 5) only the top half of the text is visible. The multiline input (6) is drawn correctly because multiline skips the centering code, but its onContentSizeChange reports contentSize 1.0 x 2.0.

RNW 0.81.36, ARM64, 96 DPI:

Image
CLI version

20.0.0

Environment
System:
  OS: Windows 11 10.0.26100
  CPU: (6) arm64 virt-10.0
  Memory: 5.24 GB / 15.99 GB
Binaries:
  Node:
    version: 22.14.0
  Yarn:
    version: 1.22.22
  npm:
    version: 10.9.2
  Watchman: Not Found
SDKs:
  Windows SDK:
    AllowDevelopmentWithoutDevLicense: Enabled
    AllowAllTrustedApps: Enabled
    Versions:
      - 10.0.19041.0
      - 10.0.22621.0
      - 10.0.26100.0
IDEs:
  Visual Studio:
    - 18.10.12217.157 (Visual Studio Professional 2026)
npmPackages:
  "@react-native-community/cli":
    installed: 20.0.0
  react:
    installed: 19.1.4
  react-native:
    installed: 0.81.5
  react-native-windows:
    installed: 0.81.36
Community Modules

none

Target React Native Architecture

New Architecture (WinAppSDK) Only

Target Platform Version

10.0.26100

Visual Studio Version

Visual Studio 2026

Build Configuration

Debug

Snack, code example, screenshot, or link to a repository

repro code is is reproduction steps

Additional notes
  • Reproduced on react-native-windows 0.81.36 (ARM64, 96 DPI). The same code is still on main. x64 builds are not affected.
  • Why only ARM64: LONG_MAX * 2540 / 96 doesn't fit in a LONG, and the out-of-range float-to-LONG conversion differs by architecture. On x64 it gives -2147483648, and a negative extent means "unconstrained" to RichEdit, so centering works there; the existing e2e snapshots on x64 CI show a correctly centered caret. On ARM64 it saturates to 2147483647, which is used as a zoom reference and shrinks the height to 0.
  • Multiline onContentSizeChange also uses GetContentSize(), so on ARM64 it reports 1.0 x 2.0 (input 6 in the screenshot).
Ngôn ngữ chính
C++
Star
17.4k
Fork
1.2k
Merge trung bình
3 ngày 10 phút
Pull request đã merge (30 ngày)
14

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của microsoft/react-native-windows

Tất cả issue của microsoft/react-native-windows

Issue tương tự

Thêm issue về C++

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.