diff --git a/.changeset/khaki-maps-lay.md b/.changeset/khaki-maps-lay.md
new file mode 100644
index 00000000..bb4b9d7d
--- /dev/null
+++ b/.changeset/khaki-maps-lay.md
@@ -0,0 +1,5 @@
+---
+'react-native-bottom-tabs': minor
+---
+
+fix: adjust the behavior of empty string for badge prop
diff --git a/apps/example/src/Examples/FourTabs.tsx b/apps/example/src/Examples/FourTabs.tsx
index 93ed60ff..4c32ece6 100644
--- a/apps/example/src/Examples/FourTabs.tsx
+++ b/apps/example/src/Examples/FourTabs.tsx
@@ -52,6 +52,7 @@ export default function FourTabs({
key: 'contacts',
focusedIcon: require('../../assets/icons/person_dark.png'),
title: 'Contacts',
+ badge: ' ',
},
{
key: 'chat',
diff --git a/docs/docs/docs/guides/standalone-usage.md b/docs/docs/docs/guides/standalone-usage.md
index a2766d21..545b9f25 100644
--- a/docs/docs/docs/guides/standalone-usage.md
+++ b/docs/docs/docs/guides/standalone-usage.md
@@ -32,12 +32,12 @@ export default function TabViewExample() {
{
key: 'home',
title: 'Home',
- focusedIcon: { sfSymbol: 'house' }
+ focusedIcon: { sfSymbol: 'house' },
},
{
key: 'settings',
title: 'Settings',
- focusedIcon: { sfSymbol: 'gear' }
+ focusedIcon: { sfSymbol: 'gear' },
},
]);
@@ -91,6 +91,7 @@ const renderScene = SceneMap({
#### `navigationState`
State for the tab view. The state should contain:
+
- `routes`: Array of route objects containing `key` and `title` props
- `index`: Current selected tab index
@@ -107,6 +108,7 @@ Callback that is called when the tab index changes.
#### `labeled`
Whether to show labels in tabs. When `false`, only icons will be displayed.
+
- Type: `boolean`
- Default : `true`
- Default : `false`
@@ -114,6 +116,7 @@ Whether to show labels in tabs. When `false`, only icons will be displayed.
#### `sidebarAdaptable`
A tab bar style that adapts to each platform:
+
- iPadOS: Top tab bar that can adapt into a sidebar
- iOS: Bottom tab bar
- macOS/tvOS: Sidebar
@@ -122,19 +125,21 @@ A tab bar style that adapts to each platform:
#### `disablePageAnimations`
Whether to disable animations between tabs.
+
- Type: `boolean`
#### `hapticFeedbackEnabled`
Whether to enable haptic feedback on tab press.
+
- Type: `boolean`
- Default: `false`
-
#### `tabLabelStyle`
Object containing styles for the tab label.
Supported properties:
+
- `fontFamily`
- `fontSize`
- `fontWeight`
@@ -142,18 +147,21 @@ Supported properties:
#### `scrollEdgeAppearance`
Appearance attributes for the tab bar when a scroll view is at the bottom.
+
- Type: `'default' | 'opaque' | 'transparent'`
#### `minimizeBehavior`
Controls how the tab bar behaves when content is scrolled.
+
- Type: `'automatic' | 'onScrollDown' | 'onScrollUp' | 'never'`
- Default: `undefined` (uses system default)
Options:
+
- `automatic`: Platform determines the behavior
- `onScrollDown`: Tab bar minimizes when scrolling down
-- `onScrollUp`: Tab bar minimizes when scrolling up
+- `onScrollUp`: Tab bar minimizes when scrolling up
- `never`: Tab bar never minimizes
:::note
@@ -163,6 +171,7 @@ This feature requires iOS 26.0 or later and is only available on iOS. On older v
#### `tabBarActiveTintColor`
Color for the active tab.
+
- Type: `ColorValue`
#### `tabBarInactiveTintColor`
@@ -182,11 +191,13 @@ Supported properties:
#### `translucent`
Whether the tab bar is translucent.
+
- Type: `boolean`
#### `activeIndicatorColor`
Color of tab indicator.
+
- Type: `ColorValue`
### Route Configuration
@@ -207,21 +218,29 @@ Each route in the `routes` array can have the following properties:
#### `getLazy`
Function to determine if a screen should be lazy loaded.
+
- Default: Uses `route.lazy`
#### `getLabelText`
Function to get the label text for a tab.
+
- Default: Uses `route.title`
#### `getBadge`
Function to get the badge text for a tab.
+
- Default: Uses `route.badge`
+:::warning
+To display a badge without text (just a dot), you need to pass a string with a space character (`" "`).
+:::
+
#### `getActiveTintColor`
Function to get the active tint color for a tab.
+
- Default: Uses `route.activeTintColor`
#### `getIcon`
@@ -230,7 +249,6 @@ Function to get the icon for a tab.
- Default: Uses `route.focusedIcon` and `route.unfocusedIcon`
-
#### `getHidden`
Function to determine if a tab should be hidden.
@@ -240,4 +258,5 @@ Function to determine if a tab should be hidden.
#### `getTestID`
Function to get the test ID for a tab item.
+
- Default: Uses `route.testID`
diff --git a/docs/docs/docs/guides/usage-with-react-navigation.mdx b/docs/docs/docs/guides/usage-with-react-navigation.mdx
index 9efcea87..c04a8c95 100644
--- a/docs/docs/docs/guides/usage-with-react-navigation.mdx
+++ b/docs/docs/docs/guides/usage-with-react-navigation.mdx
@@ -168,7 +168,7 @@ Controls how the tab bar behaves when content is scrolled.
Options:
- `automatic`: Platform determines the behavior
- `onScrollDown`: Tab bar minimizes when scrolling down
-- `onScrollUp`: Tab bar minimizes when scrolling up
+- `onScrollUp`: Tab bar minimizes when scrolling up
- `never`: Tab bar never minimizes
:::note
@@ -298,6 +298,10 @@ tabBarIcon: () => require('person.svgx')
Badge to show on the tab icon.
+:::warning
+To display a badge without text (just a dot), you need to pass a string with a space character (`" "`).
+:::
+
#### `tabBarItemHidden`
Whether the tab bar item is hidden.
diff --git a/packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabView.kt b/packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabView.kt
index ab9b1dd6..41547fd1 100644
--- a/packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabView.kt
+++ b/packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabView.kt
@@ -245,7 +245,7 @@ class ReactBottomNavigationView(context: Context) : LinearLayout(context) {
}
}
- if (item.badge.isNotEmpty()) {
+ if (item.badge?.isNotEmpty() == true) {
val badge = bottomNavigation.getOrCreateBadge(index)
badge.isVisible = true
badge.text = item.badge
diff --git a/packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt b/packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt
index 424e27ff..0e6df67b 100644
--- a/packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt
+++ b/packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt
@@ -13,7 +13,7 @@ import com.rcttabview.events.TabLongPressEvent
data class TabInfo(
val key: String,
val title: String,
- val badge: String,
+ val badge: String?,
val activeTintColor: Int?,
val hidden: Boolean,
val testID: String?
@@ -32,7 +32,7 @@ class RCTTabViewImpl {
TabInfo(
key = item.getString("key") ?: "",
title = item.getString("title") ?: "",
- badge = item.getString("badge") ?: "",
+ badge = if (item.hasKey("badge")) item.getString("badge") else null,
activeTintColor = if (item.hasKey("activeTintColor")) item.getInt("activeTintColor") else null,
hidden = if (item.hasKey("hidden")) item.getBoolean("hidden") else false,
testID = item.getString("testID")
diff --git a/packages/react-native-bottom-tabs/ios/TabViewImpl.swift b/packages/react-native-bottom-tabs/ios/TabViewImpl.swift
index 7b78993d..92b9539a 100644
--- a/packages/react-native-bottom-tabs/ios/TabViewImpl.swift
+++ b/packages/react-native-bottom-tabs/ios/TabViewImpl.swift
@@ -272,7 +272,7 @@ extension View {
@ViewBuilder
func tabBadge(_ data: String?) -> some View {
if #available(iOS 15.0, macOS 15.0, visionOS 2.0, tvOS 15.0, *) {
- if let data, !data.isEmpty {
+ if let data {
#if !os(tvOS)
self.badge(data)
#else
diff --git a/packages/react-native-bottom-tabs/ios/TabViewProvider.swift b/packages/react-native-bottom-tabs/ios/TabViewProvider.swift
index 4c2e0003..9a304713 100644
--- a/packages/react-native-bottom-tabs/ios/TabViewProvider.swift
+++ b/packages/react-native-bottom-tabs/ios/TabViewProvider.swift
@@ -8,7 +8,7 @@ import SwiftUI
public final class TabInfo: NSObject {
public let key: String
public let title: String
- public let badge: String
+ public let badge: String?
public let sfSymbol: String
public let activeTintColor: PlatformColor?
public let hidden: Bool
@@ -17,7 +17,7 @@ public final class TabInfo: NSObject {
public init(
key: String,
title: String,
- badge: String,
+ badge: String?,
sfSymbol: String,
activeTintColor: PlatformColor?,
hidden: Bool,
@@ -269,7 +269,7 @@ public final class TabInfo: NSObject {
TabInfo(
key: itemDict["key"] as? String ?? "",
title: itemDict["title"] as? String ?? "",
- badge: itemDict["badge"] as? String ?? "",
+ badge: itemDict["badge"] as? String,
sfSymbol: itemDict["sfSymbol"] as? String ?? "",
activeTintColor: RCTConvert.uiColor(itemDict["activeTintColor"] as? NSNumber),
hidden: itemDict["hidden"] as? Bool ?? false,
diff --git a/packages/react-native-bottom-tabs/src/TabView.tsx b/packages/react-native-bottom-tabs/src/TabView.tsx
index 2921f88b..ed30dd13 100644
--- a/packages/react-native-bottom-tabs/src/TabView.tsx
+++ b/packages/react-native-bottom-tabs/src/TabView.tsx
@@ -175,10 +175,10 @@ const TabView = ({
renderScene,
onIndexChange,
onTabLongPress,
- getBadge,
rippleColor,
tabBarActiveTintColor: activeTintColor,
tabBarInactiveTintColor: inactiveTintColor,
+ getBadge = ({ route }: { route: Route }) => route.badge,
getLazy = ({ route }: { route: Route }) => route.lazy,
getLabelText = ({ route }: { route: Route }) => route.title,
getIcon = ({ route, focused }: { route: Route; focused: boolean }) =>