Commit 1b92b02
fix(ios): align text to the right by default in RTL (#57634)
Summary:
On the new architecture, `<Text>` without an explicit `textAlign` behaves differently across platforms when the layout direction is RTL:
- **Android**: text aligns to the right (follows the layout direction).
- **iOS**: text stays left-aligned (ignores the layout direction).
This is a regression from the old architecture, where both platforms left text alone when `textAlign` was unset. The new arch changed Android's default, and the two platforms are now inconsistent.
This PR makes iOS match the current Android (new arch) behavior: without an explicit `textAlign`, text follows the layout direction and aligns to the right in RTL. On iOS, `Natural` alignment now resolves to `Right` under RTL.
### Open question
I aligned iOS to Android's new default, but I'm not sure it's the right call (my guts feeling think that is the right thing to do, tho). The old-arch behavior (do nothing when `textAlign` is unset) may be what's actually expected, in which case the fix should go the other way: revert Android to leave text untouched and keep iOS as-is. Happy to flip the direction if reviewers prefer that.
## Changelog:
[IOS] [FIXED] - Align text to the right by default in RTL when `textAlign` is not set, matching Android
Pull Request resolved: #57634
Test Plan:
Edit `RNTesterAppShared.js`, press the button, reload the app - comment / uncomment `Text` `textAlign` style:
```js
/**
* flow
* format
*/
import {
I18nManager,
SafeAreaView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
I18nManager.allowRTL(true);
I18nManager.swapLeftAndRightInRTL(true);
export default function App(): React.Node {
const isRTL = I18nManager.isRTL;
return (
<View style={styles.wrapper}>
<SafeAreaView style={styles.content}>
<Text style={styles.info}>I18nManager.isRTL: {String(isRTL)}</Text>
<TouchableOpacity
onPress={() => I18nManager.forceRTL(!isRTL)}
style={styles.button}>
<Text style={styles.buttonText}>Toggle RTL + reload manually</Text>
</TouchableOpacity>
<View style={styles.row}>
<View style={[styles.box, {backgroundColor: '#FF6B6B'}]}>
<Text style={styles.boxText}>1</Text>
</View>
<View style={[styles.box, {backgroundColor: '#4ECDC4'}]}>
<Text style={styles.boxText}>2</Text>
</View>
<View style={[styles.box, {backgroundColor: '#45B7D1'}]}>
<Text style={styles.boxText}>3</Text>
</View>
</View>
<Text
// style={{textAlign: 'left'}} // COMMENT / UNCOMMENT THIS
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</Text>
</SafeAreaView>
</View>
);
}
const styles = StyleSheet.create({
wrapper: {
backgroundColor: 'white',
flex: 1,
},
content: {
gap: 20,
marginHorizontal: 20,
},
info: {
fontSize: 18,
fontWeight: 'bold',
},
button: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8,
},
buttonText: {
color: 'white',
textAlign: 'center',
fontWeight: '600',
},
row: {
flexDirection: 'row',
justifyContent: 'space-around',
},
box: {
width: 60,
height: 60,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 8,
},
boxText: {
color: 'white',
fontSize: 18,
fontWeight: 'bold',
},
});
```
**Old architecture (baseline):**
| Android | iOS |
| --- | --- |
| <img width="503" height="935" alt="android - old arch" src="https://github.com/user-attachments/assets/6051bfac-ae5e-454d-94e3-b632e9062b55" /> | <img width="568" height="1084" alt="ios - old arch" src="https://github.com/user-attachments/assets/8c216962-ccf1-40d7-bd81-227331aaf288" /> |
**New architecture (before this PR, iOS diverges):**
| Android | iOS |
| --- | --- |
| <img width="503" height="935" alt="android - new arch" src="https://github.com/user-attachments/assets/35fcc60e-e172-42b8-af54-6360d4425757" /> | <img width="568" height="1084" alt="ios - new arch - not fixed" src="https://github.com/user-attachments/assets/2b558f16-94b5-4f8a-adb6-90f777e69fa0" /> |
**New architecture (after this PR, iOS fixed):**
| Android | iOS |
| --- | --- |
| <img width="503" height="935" alt="android - new arch" src="https://github.com/user-attachments/assets/35fcc60e-e172-42b8-af54-6360d4425757" /> | <img width="568" height="1084" alt="ios - new arch - fixed" src="https://github.com/user-attachments/assets/9467f96c-2ef1-46fa-8209-4f8e45b14c21" /> |
Reviewed By: javache
Differential Revision: D113244783
Pulled By: Abbondanzo
fbshipit-source-id: 75edbc2a2a2e1567de12c83375272672cc2683e91 parent 41b375e commit 1b92b02
1 file changed
Lines changed: 7 additions & 6 deletions
File tree
- packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager
Lines changed: 7 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
| 21 | + | |
22 | 22 | | |
23 | | - | |
24 | 23 | | |
| 24 | + | |
| 25 | + | |
25 | 26 | | |
26 | 27 | | |
27 | 28 | | |
| |||
212 | 213 | | |
213 | 214 | | |
214 | 215 | | |
215 | | - | |
216 | | - | |
217 | | - | |
218 | | - | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
219 | 220 | | |
220 | 221 | | |
221 | 222 | | |
| |||
0 commit comments