Add native RTL support for bottom tabs on iOS & Android with optional direction override#3613
Open
ahmedawaad1804 wants to merge 12 commits intosoftware-mansion:mainfrom
Open
Add native RTL support for bottom tabs on iOS & Android with optional direction override#3613ahmedawaad1804 wants to merge 12 commits intosoftware-mansion:mainfrom
ahmedawaad1804 wants to merge 12 commits intosoftware-mansion:mainfrom
Conversation
…ntroller mode handling
Member
|
Hey, thanks for the PR. This is great, we need it. I hope to review it somewhere this week. Will keep you up to date. |
Contributor
|
Hi, thank you for the PR. I'll push some changes and update PR description so we can land it soon. I hope you don't mind. |
Author
|
@kligarski sure thank you :D |
Author
|
@kkafar welcome , any time :) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR adds proper RTL (Right-to-Left) layout support for native bottom tabs on both iOS and Android in react-native-screens.
Previously, bottom tabs did not automatically follow the system RTL direction, which caused incorrect tab ordering and layout in RTL locales (e.g. Arabic, Hebrew).
With this change bottom tabs now follow the system layout direction by default. This brings native behavior in line with expected platform RTL handling and React Native layout conventions.
Important
@kligarski: I noticed now that this approach doesn't work with sidebar (iPad). We're looking into it.
Details
@kligarski:
Android
On Android, the direction works out-of-the-box so no custom logic is necessary.
iOS
Badges
Setting
semanticContentAttributefor_controller.tabBarand_controller.viewis not enough, e.g. badges visible through liquid glass lens are still in LTR.Simulator.Screen.Recording.-.iPhone.17.Pro.RTL.-.2026-02-19.at.16.27.18.mov
To handle this, we're using the same approach as in native stack - we set
UIView'sappearanceWhenContainedInInstancesOfClassesof the tab bar (details how it's handled in the header are here).In the future, we can consider using modern way to handle direction via trait overrides (this for iOS < 17.0 and this for iOS >= 17.0). I decided against it for now in order to maintain compatibility with approach in the header. Also, there are differences in trait propagation between iOS < 17.0 and iOS >= 17.0 that we would need to consider. I added a ticket on our internal board to research this: https://github.com/software-mansion/react-native-screens-labs/issues/987.
ScrollView
On iOS, there seems to be a very odd bug with content of the ScrollView being moved off screen after tab changes. I've created an issue on our internal board (https://github.com/software-mansion/react-native-screens-labs/issues/985) and we'll investigate this further.
Screen.Recording.2026-02-19.at.15.55.06.mov
Bottom Accessory
There seems to be a bug with bottom accessory in RTL when search role is NOT used for one of the tabs (Apple Music and Apple Podcasts use search role so the bug isn't visible).
Simulator.Screen.Recording.-.iPhone.17.Pro.RTL.-.2026-02-19.at.15.52.15.mov
Simulator.Screen.Recording.-.iPhone.17.Pro.RTL.-.2026-02-19.at.15.51.31.mov
This bug is reproducible in bare UIKit app on iOS 26.2.
Simulator.Screen.Recording.-.iPhone.17.Pro.RTL.-.2026-02-19.at.16.19.15.mov
I've added this to our internal board (https://github.com/software-mansion/react-native-screens-labs/issues/986) and we'll check whether it has been fixed in iOS 26.3/26.4 beta.
Changes
Test3598.tsxBefore
(iOS only because Android works out of the box).

After
Android
android_3613.mp4
iOS
Simulator.Screen.Recording.-.iPhone.17.Pro.RTL.-.2026-02-19.at.15.49.45.mov
Simulator.Screen.Recording.-.iPhone.17.Pro.RTL.-.2026-02-19.at.15.50.11.mov
Simulator.Screen.Recording.-.iPhone.17.Pro.RTL.-.2026-02-19.at.15.51.31.mov
Test plan
Use
Test3598,TestBottomTabs,Test3288(iOS).Tested on:
Checklist