diff --git a/apps/example/src/App.tsx b/apps/example/src/App.tsx
index ba1f7606..22604d9e 100644
--- a/apps/example/src/App.tsx
+++ b/apps/example/src/App.tsx
@@ -23,6 +23,7 @@ import { SafeAreaProvider } from 'react-native-safe-area-context';
import JSBottomTabs from './Examples/JSBottomTabs';
import ThreeTabs from './Examples/ThreeTabs';
import FourTabs from './Examples/FourTabs';
+import FourTabsRTL from './Examples/FourTabsRTL';
import MaterialBottomTabs from './Examples/MaterialBottomTabs';
import SFSymbols from './Examples/SFSymbols';
import LabeledTabs from './Examples/Labeled';
@@ -72,6 +73,9 @@ const FourTabsActiveIndicatorColor = () => {
const UnlabeledTabs = () => {
return ;
};
+const FourTabsRightToLeft = () => {
+ return ;
+};
const examples = [
{
@@ -161,6 +165,7 @@ const examples = [
name: 'Bottom Accessory View',
screenOptions: { headerShown: false },
},
+ { component: FourTabsRightToLeft, name: 'Four Tabs - RTL', platform: 'ios' },
];
function App() {
diff --git a/apps/example/src/Examples/FourTabsRTL.tsx b/apps/example/src/Examples/FourTabsRTL.tsx
new file mode 100644
index 00000000..46e43fc2
--- /dev/null
+++ b/apps/example/src/Examples/FourTabsRTL.tsx
@@ -0,0 +1,94 @@
+import TabView, { SceneMap } from 'react-native-bottom-tabs';
+import React, { useState } from 'react';
+import { Article } from '../Screens/Article';
+import { Albums } from '../Screens/Albums';
+import { Contacts } from '../Screens/Contacts';
+import { Chat } from '../Screens/Chat';
+import { I18nManager, type ColorValue } from 'react-native';
+
+interface Props {
+ disablePageAnimations?: boolean;
+ scrollEdgeAppearance?: 'default' | 'opaque' | 'transparent';
+ backgroundColor?: ColorValue;
+ translucent?: boolean;
+ hideOneTab?: boolean;
+ rippleColor?: ColorValue;
+ activeIndicatorColor?: ColorValue;
+ layoutDirection?: 'leftToRight' | 'rightToLeft';
+}
+
+const renderScene = SceneMap({
+ article: Article,
+ albums: Albums,
+ contacts: Contacts,
+ chat: Chat,
+});
+
+export default function FourTabsRTL({
+ disablePageAnimations = false,
+ scrollEdgeAppearance = 'default',
+ backgroundColor,
+ translucent = true,
+ hideOneTab = false,
+ rippleColor,
+ activeIndicatorColor,
+ layoutDirection = 'leftToRight',
+}: Props) {
+ React.useLayoutEffect(() => {
+ if (layoutDirection === 'rightToLeft') {
+ I18nManager.allowRTL(true);
+ I18nManager.forceRTL(true);
+ }
+ return () => {
+ if (layoutDirection === 'rightToLeft') {
+ I18nManager.allowRTL(false);
+ I18nManager.forceRTL(false);
+ }
+ };
+ }, [layoutDirection]);
+ const [index, setIndex] = useState(0);
+ const [routes] = useState([
+ {
+ key: 'article',
+ title: 'المقالات',
+ focusedIcon: require('../../assets/icons/article_dark.png'),
+ unfocusedIcon: require('../../assets/icons/chat_dark.png'),
+ badge: '!',
+ },
+ {
+ key: 'albums',
+ title: 'البومات',
+ focusedIcon: require('../../assets/icons/grid_dark.png'),
+ badge: '5',
+ hidden: hideOneTab,
+ },
+ {
+ key: 'contacts',
+ focusedIcon: require('../../assets/icons/person_dark.png'),
+ title: 'المتراسلين',
+ badge: ' ',
+ },
+ {
+ key: 'chat',
+ focusedIcon: require('../../assets/icons/chat_dark.png'),
+ title: 'المحادثات',
+ role: 'search',
+ },
+ ]);
+
+ return (
+
+ );
+}
diff --git a/apps/example/src/Examples/NativeBottomTabs.tsx b/apps/example/src/Examples/NativeBottomTabs.tsx
index 190db787..7e89aa3a 100644
--- a/apps/example/src/Examples/NativeBottomTabs.tsx
+++ b/apps/example/src/Examples/NativeBottomTabs.tsx
@@ -15,6 +15,7 @@ function NativeBottomTabs() {
initialRouteName="Chat"
labeled={true}
hapticFeedbackEnabled={false}
+ layoutDirection="leftToRight"
tabBarInactiveTintColor="#C57B57"
tabBarActiveTintColor="#F7DBA7"
tabBarStyle={{
diff --git a/packages/react-native-bottom-tabs/ios/RCTTabViewComponentView.mm b/packages/react-native-bottom-tabs/ios/RCTTabViewComponentView.mm
index c41f9316..92cab0e7 100644
--- a/packages/react-native-bottom-tabs/ios/RCTTabViewComponentView.mm
+++ b/packages/react-native-bottom-tabs/ios/RCTTabViewComponentView.mm
@@ -160,6 +160,10 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
_tabViewProvider.hapticFeedbackEnabled = newViewProps.hapticFeedbackEnabled;
}
+ if (oldViewProps.layoutDirection != newViewProps.layoutDirection) {
+ _tabViewProvider.layoutDirection = RCTNSStringFromStringNilIfEmpty(newViewProps.layoutDirection);
+ }
+
if (oldViewProps.fontSize != newViewProps.fontSize) {
_tabViewProvider.fontSize = [NSNumber numberWithInt:newViewProps.fontSize];
}
diff --git a/packages/react-native-bottom-tabs/ios/TabView/NewTabView.swift b/packages/react-native-bottom-tabs/ios/TabView/NewTabView.swift
index d6993158..f878f8ca 100644
--- a/packages/react-native-bottom-tabs/ios/TabView/NewTabView.swift
+++ b/packages/react-native-bottom-tabs/ios/TabView/NewTabView.swift
@@ -11,6 +11,12 @@ struct NewTabView: AnyTabView {
@ViewBuilder
var body: some View {
+ var effectiveLayoutDirection: LayoutDirection {
+ if let layoutDirectionString = props.layoutDirection {
+ return layoutDirectionString == "rightToLeft" ? .rightToLeft : .leftToRight
+ }
+ return .leftToRight
+ }
TabView(selection: $props.selectedPage) {
ForEach(props.children) { child in
if let index = props.children.firstIndex(of: child),
@@ -49,6 +55,7 @@ struct NewTabView: AnyTabView {
}
}
}
+ .environment(\.layoutDirection, effectiveLayoutDirection)
.measureView { size in
onLayout(size)
}
diff --git a/packages/react-native-bottom-tabs/ios/TabViewProps.swift b/packages/react-native-bottom-tabs/ios/TabViewProps.swift
index cd098c07..2670ac99 100644
--- a/packages/react-native-bottom-tabs/ios/TabViewProps.swift
+++ b/packages/react-native-bottom-tabs/ios/TabViewProps.swift
@@ -66,6 +66,7 @@ class TabViewProps: ObservableObject {
@Published var translucent: Bool = true
@Published var disablePageAnimations: Bool = false
@Published var hapticFeedbackEnabled: Bool = false
+ @Published var layoutDirection: String?
@Published var fontSize: Int?
@Published var fontFamily: String?
@Published var fontWeight: String?
diff --git a/packages/react-native-bottom-tabs/ios/TabViewProvider.swift b/packages/react-native-bottom-tabs/ios/TabViewProvider.swift
index 013032f0..a03378f7 100644
--- a/packages/react-native-bottom-tabs/ios/TabViewProvider.swift
+++ b/packages/react-native-bottom-tabs/ios/TabViewProvider.swift
@@ -95,6 +95,12 @@ public final class TabInfo: NSObject {
}
}
+ @objc public var layoutDirection: NSString? {
+ didSet {
+ props.layoutDirection = layoutDirection as? String
+ }
+ }
+
@objc public var scrollEdgeAppearance: NSString? {
didSet {
props.scrollEdgeAppearance = scrollEdgeAppearance as? String
@@ -155,6 +161,8 @@ public final class TabInfo: NSObject {
}
}
+
+
@objc public var itemsData: [TabInfo] = [] {
didSet {
props.items = itemsData
diff --git a/packages/react-native-bottom-tabs/src/TabView.tsx b/packages/react-native-bottom-tabs/src/TabView.tsx
index 41b9cb37..3c04172d 100644
--- a/packages/react-native-bottom-tabs/src/TabView.tsx
+++ b/packages/react-native-bottom-tabs/src/TabView.tsx
@@ -201,6 +201,12 @@ interface Props {
* @platform ios
*/
renderBottomAccessoryView?: BottomAccessoryViewProps['renderBottomAccessoryView'];
+ /**
+ * The direction of the layout. (iOS only)
+ * @platform ios
+ * @default 'leftToRight'
+ */
+ layoutDirection?: 'leftToRight' | 'rightToLeft';
}
const ANDROID_MAX_TABS = 100;
@@ -239,6 +245,7 @@ const TabView = ({
tabBarStyle,
tabLabelStyle,
renderBottomAccessoryView,
+ layoutDirection = 'leftToRight',
...props
}: Props) => {
// @ts-ignore
@@ -398,6 +405,7 @@ const TabView = ({
onTabBarMeasured={handleTabBarMeasured}
onNativeLayout={handleNativeLayout}
hapticFeedbackEnabled={hapticFeedbackEnabled}
+ layoutDirection={layoutDirection}
activeTintColor={activeTintColor}
inactiveTintColor={inactiveTintColor}
barTintColor={tabBarStyle?.backgroundColor}
diff --git a/packages/react-native-bottom-tabs/src/TabViewNativeComponent.ts b/packages/react-native-bottom-tabs/src/TabViewNativeComponent.ts
index 7949e156..50082c55 100644
--- a/packages/react-native-bottom-tabs/src/TabViewNativeComponent.ts
+++ b/packages/react-native-bottom-tabs/src/TabViewNativeComponent.ts
@@ -56,6 +56,7 @@ export interface TabViewProps extends ViewProps {
disablePageAnimations?: boolean;
activeIndicatorColor?: ColorValue;
hapticFeedbackEnabled?: boolean;
+ layoutDirection?: string;
minimizeBehavior?: string;
fontFamily?: string;
fontWeight?: string;