Skip to content

Commit e9b06e7

Browse files
authored
fix: adjust behavior of empty string in badge prop (#378)
1 parent 89b6a5b commit e9b06e7

File tree

9 files changed

+43
-14
lines changed

9 files changed

+43
-14
lines changed

.changeset/khaki-maps-lay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'react-native-bottom-tabs': minor
3+
---
4+
5+
fix: adjust the behavior of empty string for badge prop

apps/example/src/Examples/FourTabs.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export default function FourTabs({
5252
key: 'contacts',
5353
focusedIcon: require('../../assets/icons/person_dark.png'),
5454
title: 'Contacts',
55+
badge: ' ',
5556
},
5657
{
5758
key: 'chat',

docs/docs/docs/guides/standalone-usage.md

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ export default function TabViewExample() {
3232
{
3333
key: 'home',
3434
title: 'Home',
35-
focusedIcon: { sfSymbol: 'house' }
35+
focusedIcon: { sfSymbol: 'house' },
3636
},
3737
{
3838
key: 'settings',
3939
title: 'Settings',
40-
focusedIcon: { sfSymbol: 'gear' }
40+
focusedIcon: { sfSymbol: 'gear' },
4141
},
4242
]);
4343

@@ -91,6 +91,7 @@ const renderScene = SceneMap({
9191
#### `navigationState`
9292

9393
State for the tab view. The state should contain:
94+
9495
- `routes`: Array of route objects containing `key` and `title` props
9596
- `index`: Current selected tab index
9697

@@ -107,13 +108,15 @@ Callback that is called when the tab index changes.
107108
#### `labeled`
108109

109110
Whether to show labels in tabs. When `false`, only icons will be displayed.
111+
110112
- Type: `boolean`
111113
- Default <Badge text="iOS" type="info" />: `true`
112114
- Default <Badge text="Android" type="info" />: `false`
113115

114116
#### `sidebarAdaptable` <Badge text="iOS" type="info" />
115117

116118
A tab bar style that adapts to each platform:
119+
117120
- iPadOS: Top tab bar that can adapt into a sidebar
118121
- iOS: Bottom tab bar
119122
- macOS/tvOS: Sidebar
@@ -122,38 +125,43 @@ A tab bar style that adapts to each platform:
122125
#### `disablePageAnimations` <Badge text="iOS" type="info" />
123126

124127
Whether to disable animations between tabs.
128+
125129
- Type: `boolean`
126130

127131
#### `hapticFeedbackEnabled`
128132

129133
Whether to enable haptic feedback on tab press.
134+
130135
- Type: `boolean`
131136
- Default: `false`
132137

133-
134138
#### `tabLabelStyle`
135139

136140
Object containing styles for the tab label.
137141
Supported properties:
142+
138143
- `fontFamily`
139144
- `fontSize`
140145
- `fontWeight`
141146

142147
#### `scrollEdgeAppearance` <Badge text="iOS" type="info" />
143148

144149
Appearance attributes for the tab bar when a scroll view is at the bottom.
150+
145151
- Type: `'default' | 'opaque' | 'transparent'`
146152

147153
#### `minimizeBehavior` <Badge text="iOS 26+" type="info" />
148154

149155
Controls how the tab bar behaves when content is scrolled.
156+
150157
- Type: `'automatic' | 'onScrollDown' | 'onScrollUp' | 'never'`
151158
- Default: `undefined` (uses system default)
152159

153160
Options:
161+
154162
- `automatic`: Platform determines the behavior
155163
- `onScrollDown`: Tab bar minimizes when scrolling down
156-
- `onScrollUp`: Tab bar minimizes when scrolling up
164+
- `onScrollUp`: Tab bar minimizes when scrolling up
157165
- `never`: Tab bar never minimizes
158166

159167
:::note
@@ -163,6 +171,7 @@ This feature requires iOS 26.0 or later and is only available on iOS. On older v
163171
#### `tabBarActiveTintColor`
164172

165173
Color for the active tab.
174+
166175
- Type: `ColorValue`
167176

168177
#### `tabBarInactiveTintColor`
@@ -182,11 +191,13 @@ Supported properties:
182191
#### `translucent` <Badge text="iOS" type="info" />
183192

184193
Whether the tab bar is translucent.
194+
185195
- Type: `boolean`
186196

187197
#### `activeIndicatorColor` <Badge text="Android" type="info" />
188198

189199
Color of tab indicator.
200+
190201
- Type: `ColorValue`
191202

192203
### Route Configuration
@@ -207,21 +218,29 @@ Each route in the `routes` array can have the following properties:
207218
#### `getLazy`
208219

209220
Function to determine if a screen should be lazy loaded.
221+
210222
- Default: Uses `route.lazy`
211223

212224
#### `getLabelText`
213225

214226
Function to get the label text for a tab.
227+
215228
- Default: Uses `route.title`
216229

217230
#### `getBadge`
218231

219232
Function to get the badge text for a tab.
233+
220234
- Default: Uses `route.badge`
221235

236+
:::warning
237+
To display a badge without text (just a dot), you need to pass a string with a space character (`" "`).
238+
:::
239+
222240
#### `getActiveTintColor`
223241

224242
Function to get the active tint color for a tab.
243+
225244
- Default: Uses `route.activeTintColor`
226245

227246
#### `getIcon`
@@ -230,7 +249,6 @@ Function to get the icon for a tab.
230249

231250
- Default: Uses `route.focusedIcon` and `route.unfocusedIcon`
232251

233-
234252
#### `getHidden`
235253

236254
Function to determine if a tab should be hidden.
@@ -240,4 +258,5 @@ Function to determine if a tab should be hidden.
240258
#### `getTestID`
241259

242260
Function to get the test ID for a tab item.
261+
243262
- Default: Uses `route.testID`

docs/docs/docs/guides/usage-with-react-navigation.mdx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ Controls how the tab bar behaves when content is scrolled.
168168
Options:
169169
- `automatic`: Platform determines the behavior
170170
- `onScrollDown`: Tab bar minimizes when scrolling down
171-
- `onScrollUp`: Tab bar minimizes when scrolling up
171+
- `onScrollUp`: Tab bar minimizes when scrolling up
172172
- `never`: Tab bar never minimizes
173173

174174
:::note
@@ -298,6 +298,10 @@ tabBarIcon: () => require('person.svgx')
298298

299299
Badge to show on the tab icon.
300300

301+
:::warning
302+
To display a badge without text (just a dot), you need to pass a string with a space character (`" "`).
303+
:::
304+
301305
#### `tabBarItemHidden`
302306

303307
Whether the tab bar item is hidden.

packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ class ReactBottomNavigationView(context: Context) : LinearLayout(context) {
245245
}
246246
}
247247

248-
if (item.badge.isNotEmpty()) {
248+
if (item.badge?.isNotEmpty() == true) {
249249
val badge = bottomNavigation.getOrCreateBadge(index)
250250
badge.isVisible = true
251251
badge.text = item.badge

packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import com.rcttabview.events.TabLongPressEvent
1313
data class TabInfo(
1414
val key: String,
1515
val title: String,
16-
val badge: String,
16+
val badge: String?,
1717
val activeTintColor: Int?,
1818
val hidden: Boolean,
1919
val testID: String?
@@ -32,7 +32,7 @@ class RCTTabViewImpl {
3232
TabInfo(
3333
key = item.getString("key") ?: "",
3434
title = item.getString("title") ?: "",
35-
badge = item.getString("badge") ?: "",
35+
badge = if (item.hasKey("badge")) item.getString("badge") else null,
3636
activeTintColor = if (item.hasKey("activeTintColor")) item.getInt("activeTintColor") else null,
3737
hidden = if (item.hasKey("hidden")) item.getBoolean("hidden") else false,
3838
testID = item.getString("testID")

packages/react-native-bottom-tabs/ios/TabViewImpl.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ extension View {
272272
@ViewBuilder
273273
func tabBadge(_ data: String?) -> some View {
274274
if #available(iOS 15.0, macOS 15.0, visionOS 2.0, tvOS 15.0, *) {
275-
if let data, !data.isEmpty {
275+
if let data {
276276
#if !os(tvOS)
277277
self.badge(data)
278278
#else

packages/react-native-bottom-tabs/ios/TabViewProvider.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import SwiftUI
88
public final class TabInfo: NSObject {
99
public let key: String
1010
public let title: String
11-
public let badge: String
11+
public let badge: String?
1212
public let sfSymbol: String
1313
public let activeTintColor: PlatformColor?
1414
public let hidden: Bool
@@ -17,7 +17,7 @@ public final class TabInfo: NSObject {
1717
public init(
1818
key: String,
1919
title: String,
20-
badge: String,
20+
badge: String?,
2121
sfSymbol: String,
2222
activeTintColor: PlatformColor?,
2323
hidden: Bool,
@@ -269,7 +269,7 @@ public final class TabInfo: NSObject {
269269
TabInfo(
270270
key: itemDict["key"] as? String ?? "",
271271
title: itemDict["title"] as? String ?? "",
272-
badge: itemDict["badge"] as? String ?? "",
272+
badge: itemDict["badge"] as? String,
273273
sfSymbol: itemDict["sfSymbol"] as? String ?? "",
274274
activeTintColor: RCTConvert.uiColor(itemDict["activeTintColor"] as? NSNumber),
275275
hidden: itemDict["hidden"] as? Bool ?? false,

packages/react-native-bottom-tabs/src/TabView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,10 @@ const TabView = <Route extends BaseRoute>({
175175
renderScene,
176176
onIndexChange,
177177
onTabLongPress,
178-
getBadge,
179178
rippleColor,
180179
tabBarActiveTintColor: activeTintColor,
181180
tabBarInactiveTintColor: inactiveTintColor,
181+
getBadge = ({ route }: { route: Route }) => route.badge,
182182
getLazy = ({ route }: { route: Route }) => route.lazy,
183183
getLabelText = ({ route }: { route: Route }) => route.title,
184184
getIcon = ({ route, focused }: { route: Route; focused: boolean }) =>

0 commit comments

Comments
 (0)