Skip to content

TextAlign and WritingDirection Parity for Fabric TextInput#15340

Merged
Nitin-100 merged 6 commits intomicrosoft:mainfrom
Nitin-100:nitin/parity-fabric/textalign-writingdirection
Nov 18, 2025
Merged

TextAlign and WritingDirection Parity for Fabric TextInput#15340
Nitin-100 merged 6 commits intomicrosoft:mainfrom
Nitin-100:nitin/parity-fabric/textalign-writingdirection

Conversation

@Nitin-100
Copy link
Copy Markdown
Contributor

@Nitin-100 Nitin-100 commented Nov 9, 2025

Description

Type of Change

  • Bug fix (non-breaking change which fixes missing functionality)
  • Feature addition (non-breaking change which adds missing property support)

Why

The Fabric Composition architecture had incomplete support for the textAlign property and no support for the writingDirection property in TextInput components. Specifically:

  1. textAlign: Fabric was missing support for the 'justify' alignment option that Paper XAML fully supports
  2. textAlign='auto': The Natural/auto alignment wasn't respecting RTL (right-to-left) writing direction as intended
  3. writingDirection: This property was completely unimplemented in Fabric, even though it's defined in React Native's TextAttributes and Paper supports it via FlowDirection

This created feature gaps where:

  • Users couldn't justify text in Fabric TextInputs (common for long-form text)
  • RTL language support was incomplete - auto alignment always defaulted to left
  • There was no way to explicitly set text direction for internationalized apps
  • The existing commented RTL code in UpdateParaFormat was never activated

What

Implemented complete textAlign and writingDirection support in Fabric TextInput to achieve full parity with Paper XAML implementation:

1. textAlign Property Enhancements:

  • Added support for 'justify' alignment using RichEdit's PFA_JUSTIFY flag
  • Fixed 'auto'/Natural alignment to properly respect writing direction:
    • When writingDirection='rtl' and textAlign='auto' → aligns right
    • When writingDirection='ltr' and textAlign='auto' → aligns left
    • Default behavior remains left-aligned

2. writingDirection Property Implementation:

  • Reads baseWritingDirection from TextAttributes (inherited from BaseTextProps)
  • Supports all three values:
    • 'ltr' (Left-to-Right): Explicitly sets LTR paragraph direction
    • 'rtl' (Right-to-Left): Sets PFM_RTLPARA and PFE_RTLPARA flags in RichEdit
    • 'auto'/Natural: Uses default behavior (no explicit RTL flags)
  • Replaces the previously commented-out RTL code with proper implementation

Technical Implementation:
Modified WindowsTextInputComponentView::UpdateParaFormat() to:

// Read writingDirection from textAttributes
auto &baseWritingDirection = windowsTextInputProps().textAttributes.baseWritingDirection;

// Set RTL flags when writingDirection='rtl'
if (*baseWritingDirection == WritingDirection::RightToLeft) {
    m_pf.dwMask |= PFM_RTLPARA;
    m_pf.wEffects |= PFE_RTLPARA;
}

// Make textAlign='auto' respect writing direction
if (textAlign == TextAlignment::Natural) {
    m_pf.wAlignment = isRTL ? PFA_RIGHT : PFA_LEFT;
}

This implementation leverages RichEdit's native paragraph formatting capabilities through the PARAFORMAT2 structure, ensuring proper rendering of both alignment and text direction.

Screenshots

No screenshots needed. This implements standard text alignment and direction behaviors that match Paper architecture.

Testing

textAlign='justify' Testing:

  1. Created TextInput with long multiline text and textAlign='justify'
  2. Verified text is fully justified across all lines except the last line
  3. Compared with Paper (playground.sln) - identical rendering

textAlign='auto' with RTL Testing:

  1. TextInput with textAlign='auto' and writingDirection='ltr' → text aligns left
  2. TextInput with textAlign='auto' and writingDirection='rtl' → text aligns right
  3. Verified behavior matches Paper's FlowDirection implementation

writingDirection Explicit Testing:

  1. Arabic/Hebrew text with writingDirection='rtl':
    • Text flows right-to-left correctly
    • Cursor starts on the right
    • Selection direction is RTL
  2. English text with writingDirection='ltr':
    • Explicit LTR behavior even in RTL context
  3. writingDirection='auto':
    • Uses system default based on content

All textAlign Values Verified:

  • 'left' → PFA_LEFT
  • 'right' → PFA_RIGHT
  • 'center' → PFA_CENTER
  • 'justify' → PFA_JUSTIFY (NEW)
  • 'auto' → Respects RTL (FIXED)

Changelog

Should this change be included in the release notes: yes

Implemented complete textAlign and writingDirection support for Fabric TextInput. Users can now justify text alignment and control text direction for internationalized applications. The textAlign='auto' option now properly respects RTL writing direction. This achieves full parity with Paper XAML implementation and improves support for right-to-left languages.

Related Work

  • Removes previously commented RTL code and replaces it with proper implementation
  • BaseTextProps already includes writingDirection property through TextAttributes
  • Paper XAML uses TryUpdateFlowDirection for similar functionality
  • This complements existing TextInput internationalization features

Breaking Changes

None. These are additive features that don't change existing behavior.

Microsoft Reviewers: Open in CodeFlow

Nitin Chaudhary added 2 commits November 9, 2025 20:17
…xtInput

- Add support for textAlign='justify' using PFA_JUSTIFY flag
- Implement writingDirection (baseWritingDirection) support for 'ltr', 'rtl', and 'auto'
- Make textAlign='auto' (Natural) respect RTL writing direction
- Set PFM_RTLPARA and PFE_RTLPARA flags for RTL text
- Achieves full parity with Paper XAML implementation
@Nitin-100 Nitin-100 requested a review from a team as a code owner November 9, 2025 14:52
// Ensure RTL flag is not set
m_pf.wEffects &= ~PFE_RTLPARA;
}
// WritingDirection::Natural uses default behavior (no specific RTL setting)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think in this case the direction needs to come from layoutMetrics().layoutDirection, since direction could be overridden at any point in the tree?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

m_pf.cTabCount = 1;
m_pf.rgxTabs[0] = lDefaultTab;

/*
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lets delete the old code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

@acoates-ms
Copy link
Copy Markdown
Contributor

Can any of these flags affect layout? If so, similar changes will be needed in WindowsTextLayoutManager - which is where layout is performed.

@Nitin-100
Copy link
Copy Markdown
Contributor Author

Can any of these flags affect layout? If so, similar changes will be needed in WindowsTextLayoutManager - which is where layout is performed.

Yes, the PFE_RTLPARA and PFA_LEFT/RIGHT/CENTER/JUSTIFY flags DO affect text layout and measurement. However, WindowsTextLayoutManager currently does NOT handle baseWritingDirection/WritingDirection - it only handles TextAlignment.
To fully support this, WindowsTextLayoutManager would need:
1.Call SetReadingDirection(DWRITE_READING_DIRECTION_RIGHT_TO_LEFT) on the IDWriteTextFormat or IDWriteTextLayout
2.Handle WritingDirection::Natural by checking layoutConstraints.layoutDirection (similar to what ParagraphShadowNode does in getContent())

Nitin Chaudhary added 2 commits November 11, 2025 09:19
- TextInput now properly handles textAlign (Left, Right, Center, Justified, Natural)
- TextInput now properly handles writingDirection/baseWritingDirection (LTR, RTL, Natural)
- WritingDirection::Natural uses layoutMetrics.layoutDirection since direction can be
  overridden at any point in the tree
- Added matching support in WindowsTextLayoutManager for text measurement
- WindowsTextLayoutManager now sets DWRITE_READING_DIRECTION based on baseWritingDirection
- TextAlignment::Natural now respects reading direction (RTL = trailing, LTR = leading)
- Fixes layout affecting flags that impact text measurement throughout the system
- Only call SetReadingDirection when baseWritingDirection is explicitly specified
- Avoids breaking existing text layouts that don't specify writingDirection
- Fixes LegacyControlStyleTest snapshot failure
- Natural alignment still respects RTL when baseWritingDirection is set
@acoates-ms
Copy link
Copy Markdown
Contributor

Can any of these flags affect layout? If so, similar changes will be needed in WindowsTextLayoutManager - which is where layout is performed.

Yes, the PFE_RTLPARA and PFA_LEFT/RIGHT/CENTER/JUSTIFY flags DO affect text layout and measurement. However, WindowsTextLayoutManager currently does NOT handle baseWritingDirection/WritingDirection - it only handles TextAlignment. To fully support this, WindowsTextLayoutManager would need: 1.Call SetReadingDirection(DWRITE_READING_DIRECTION_RIGHT_TO_LEFT) on the IDWriteTextFormat or IDWriteTextLayout 2.Handle WritingDirection::Natural by checking layoutConstraints.layoutDirection (similar to what ParagraphShadowNode does in getContent())

Can we fix that? We cannot have TextInput and TextLayoutManager disagree on the size, otherwise we'll get bad sizing behaviors in certain layouts.

@Nitin-100
Copy link
Copy Markdown
Contributor Author

Can any of these flags affect layout? If so, similar changes will be needed in WindowsTextLayoutManager - which is where layout is performed.

Yes, the PFE_RTLPARA and PFA_LEFT/RIGHT/CENTER/JUSTIFY flags DO affect text layout and measurement. However, WindowsTextLayoutManager currently does NOT handle baseWritingDirection/WritingDirection - it only handles TextAlignment. To fully support this, WindowsTextLayoutManager would need: 1.Call SetReadingDirection(DWRITE_READING_DIRECTION_RIGHT_TO_LEFT) on the IDWriteTextFormat or IDWriteTextLayout 2.Handle WritingDirection::Natural by checking layoutConstraints.layoutDirection (similar to what ParagraphShadowNode does in getContent())

Can we fix that? We cannot have TextInput and TextLayoutManager disagree on the size, otherwise we'll get bad sizing behaviors in certain layouts.

Done that in the latest commit.

@Nitin-100 Nitin-100 merged commit 5bc336f into microsoft:main Nov 18, 2025
30 checks passed
Nitin-100 added a commit that referenced this pull request Nov 21, 2025
* Change files

* Implement textAlign justify and writingDirection support in Fabric TextInput

- Add support for textAlign='justify' using PFA_JUSTIFY flag
- Implement writingDirection (baseWritingDirection) support for 'ltr', 'rtl', and 'auto'
- Make textAlign='auto' (Natural) respect RTL writing direction
- Set PFM_RTLPARA and PFE_RTLPARA flags for RTL text
- Achieves full parity with Paper XAML implementation

* Fix beachball change file - add meaningful comment

* Add textAlign and writingDirection support to TextInput and text layout

- TextInput now properly handles textAlign (Left, Right, Center, Justified, Natural)
- TextInput now properly handles writingDirection/baseWritingDirection (LTR, RTL, Natural)
- WritingDirection::Natural uses layoutMetrics.layoutDirection since direction can be
  overridden at any point in the tree
- Added matching support in WindowsTextLayoutManager for text measurement
- WindowsTextLayoutManager now sets DWRITE_READING_DIRECTION based on baseWritingDirection
- TextAlignment::Natural now respects reading direction (RTL = trailing, LTR = leading)
- Fixes layout affecting flags that impact text measurement throughout the system

* Fix reading direction to only apply when explicitly set

- Only call SetReadingDirection when baseWritingDirection is explicitly specified
- Avoids breaking existing text layouts that don't specify writingDirection
- Fixes LegacyControlStyleTest snapshot failure
- Natural alignment still respects RTL when baseWritingDirection is set

---------

Co-authored-by: Nitin Chaudhary <nitchaudhary@microsoft.com>
vineethkuttan added a commit that referenced this pull request Nov 25, 2025
* ContextMenu implementation in Fabric as per Parity to Paper  (#15339)

* Change files

* Implement context menu support for Fabric TextInput with contextMenuHidden property

* Fix beachball change file - add meaningful comment

* Fix context menu Paste option to check clipboard content

- Added clipboard content check using IsClipboardFormatAvailable(CF_UNICODETEXT)
- Paste menu item now only enabled when clipboard has text AND field is editable
- Fixes bug where Cut/Copy/Paste showed even when text field was empty
- Matches XAML TextBox automatic clipboard state checking behavior

Menu item logic now matches Paper:
- Cut: requires selection AND editable
- Copy: requires selection only
- Paste: requires editable AND clipboard has text content
- Select All: requires non-empty text AND editable

* Fix context menu to show on button release (WM_RBUTTONUP) instead of press

---------

Co-authored-by: Nitin Chaudhary <nitchaudhary@microsoft.com>

* TextAlign and WritingDirection Parity for Fabric TextInput (#15340)

* Change files

* Implement textAlign justify and writingDirection support in Fabric TextInput

- Add support for textAlign='justify' using PFA_JUSTIFY flag
- Implement writingDirection (baseWritingDirection) support for 'ltr', 'rtl', and 'auto'
- Make textAlign='auto' (Natural) respect RTL writing direction
- Set PFM_RTLPARA and PFE_RTLPARA flags for RTL text
- Achieves full parity with Paper XAML implementation

* Fix beachball change file - add meaningful comment

* Add textAlign and writingDirection support to TextInput and text layout

- TextInput now properly handles textAlign (Left, Right, Center, Justified, Natural)
- TextInput now properly handles writingDirection/baseWritingDirection (LTR, RTL, Natural)
- WritingDirection::Natural uses layoutMetrics.layoutDirection since direction can be
  overridden at any point in the tree
- Added matching support in WindowsTextLayoutManager for text measurement
- WindowsTextLayoutManager now sets DWRITE_READING_DIRECTION based on baseWritingDirection
- TextAlignment::Natural now respects reading direction (RTL = trailing, LTR = leading)
- Fixes layout affecting flags that impact text measurement throughout the system

* Fix reading direction to only apply when explicitly set

- Only call SetReadingDirection when baseWritingDirection is explicitly specified
- Avoids breaking existing text layouts that don't specify writingDirection
- Fixes LegacyControlStyleTest snapshot failure
- Natural alignment still respects RTL when baseWritingDirection is set

---------

Co-authored-by: Nitin Chaudhary <nitchaudhary@microsoft.com>

* PagingEnabled Parity for Fabric ScrollView (#15341)

* Implement pagingEnabled prop for Fabric ScrollView

- Add pagingEnabled boolean member to CompScrollerVisual
- Implement PagingEnabled() method in IScrollVisual interface
- Generate viewport-sized snap points when pagingEnabled=true
- Wire up pagingEnabled prop in ScrollViewComponentView::updateProps()
- Achieves parity with Paper ScrollView pagingEnabled support

* Implement pagingEnabled property for Fabric ScrollView

- Added bool m_pagingEnabled member to CompScrollerVisual
- Implemented PagingEnabled() method in IScrollVisual interface
- Generate viewport-sized snap points when pagingEnabled=true
- Wired up prop handling in ScrollViewComponentView
- snapToOffsets disables pagingEnabled (matches Paper/iOS/Android behavior)
- Excludes snapToEnd when pagingEnabled to avoid conflicts
- Validates viewport size before generating snap points
- Reconfigures snap points when size changes and paging is enabled

Achieves full parity with Paper XAML and cross-platform React Native behavior.

* Implement snapToInterval and snapToAlignment for Fabric ScrollView

Added complete snap point parity with Paper/iOS/Android:

1. pagingEnabled: Snaps to viewport-size intervals
   - Already implemented in previous commit
   - Full page-by-page scrolling behavior

2. snapToInterval: Snaps to fixed interval multiples
   - More flexible than pagingEnabled
   - Works with any interval value
   - Generates snap points at: 0, interval, 2*interval, 3*interval, ... maxScroll

3. snapToAlignment: Controls snap point alignment
   - Values: 'start' (Near), 'center' (Center), 'end' (Far)
   - Only applies when snapToInterval is set
   - Start: no offset (default)
   - Center: offset = -viewport/2
   - End: offset = -viewport

Priority hierarchy matches React Native official behavior:
- snapToOffsets (highest) > snapToInterval > pagingEnabled > snapToStart/snapToEnd

Implementation:
- Added SnapPointsAlignment enum to CompositionSwitcher.idl
- Added m_snapToInterval and m_snapToAlignment members to CompScrollerVisual
- Implemented SnapToInterval() and SnapToAlignment() methods
- Updated ConfigureSnapInertiaModifiers() with priority-based snap point generation
- Wired props in ScrollViewComponentView::updateProps()
- snapToOffsets disables both snapToInterval and pagingEnabled

Matches Paper's SnapPointManagingContentControl behavior where:
- GetRegularSnapPoints() returns m_interval when set
- SnapToOffsets() sets m_interval = 0 (disables it)
- XAML SnapPointsAlignment maps to: Near=start, Center=center, Far=end

* Fix snapToInterval type - Float not optional

* Update change file and fix formatting for snap point implementation

---------

Co-authored-by: Nitin Chaudhary <nitchaudhary@microsoft.com>

---------

Co-authored-by: Nitin Chaudhary <nitchaudhary@microsoft.com>
Co-authored-by: Vineeth <66076509+vineethkuttan@users.noreply.github.com>
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.

2 participants