Skip to content

tabBarHidden navigator prop is silently ignored — hardcoded in JS wrapper #521

@davidecallegaro

Description

@davidecallegaro

Summary

tabBarHidden is documented and wired up natively (Swift .hideTabBar(props.tabBarHidden), addressed in #76), but the JS wrapper in packages/react-native-bottom-tabs/src/TabView.tsx hardcodes it on the inner NativeTabView, so any user-supplied value is silently overwritten before it reaches native.

Repro

import TabView from 'react-native-bottom-tabs';

// — or with the React Navigation adapter —
// <Tabs.Navigator tabBarHidden={shouldHide}>

<TabView
  navigationState={{ index, routes }}
  renderScene={renderScene}
  onIndexChange={setIndex}
  tabBarHidden={shouldHide}   // ← never reaches native
/>

Expected: the native tab bar is hidden via SwiftUI's .hideTabBar(true) when shouldHide === true.

Actual: tab bar stays visible regardless of the value passed. The user-supplied prop is shadowed inside TabView.tsx by:

// packages/react-native-bottom-tabs/src/TabView.tsx (~line 395 on `main`)
<NativeTabView
  {...props}
  ...
  tabBarHidden={!!renderCustomTabBar}   // ← overwrites props.tabBarHidden
  ...
/>

The compiled output in lib/module/TabView.js has the same shape:

tabBarHidden: !!renderCustomTabBar,

Because the line is after {...props}, JSX prop precedence wins and the user's tabBarHidden is discarded.

Why this matters on iOS 26

External native-module workarounds that wrote to UITabBar.isHidden from a UIWindowScene traversal worked on iOS ≤ 18 but stopped working on iOS 26, because the SwiftUI host now reconciles the bar's isHidden from props.tabBarHidden on every appearance pass (TabViewImpl.swift updateTabBarAppearance). With the JS wrapper hardcoding tabBarHidden = !!renderCustomTabBar, that prop is always false for non-custom-tab-bar consumers — so any external attempt to hide is clobbered.

Net effect: there is currently no working path for an app to per-screen hide the native tab bar on iOS 26 without forking or patching the library.

Proposed fix

Honor a user-supplied tabBarHidden when set; fall back to the existing "hide when custom tab bar is rendered" behavior otherwise.

   <NativeTabView
     {...props}
     {...tabLabelStyle}
     style={styles.fullWidth}
     items={items}
     // When rendering a custom tab bar, icons can be React elements, which will not be properly resolved.
     icons={renderCustomTabBar ? undefined : resolvedIconAssets}
     selectedPage={focusedKey}
-    tabBarHidden={!!renderCustomTabBar}
+    tabBarHidden={props.tabBarHidden ?? !!renderCustomTabBar}

That preserves backwards compatibility (default behavior is unchanged for any consumer that doesn't pass tabBarHidden) and unblocks the documented use case.

Happy to open a PR.

Environment

  • react-native-bottom-tabs 1.1.0 (also present on main as of this filing)
  • @bottom-tabs/react-navigation 1.0.x
  • iOS 26 SDK, real device (iPhone 15 Pro Max)
  • React Native 0.81.x, Expo SDK 54

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions