The TabView component is a navigation component that is usually at the base of a mobile app. As such it's very important to get it right. Following lots of reported issues and discussions, we decided to do a re-design of how the developer uses and customizes the component. This should be done by introducing several new components including BottomNavigation
and Tabs
and there should be no breaking changes for existing apps. See the design doc below for the detailed information.
Implementation details and motivation of the feature can be found in its design document.
NativeScript 6.0 (components released as BETA / EXPERIMENTAL)
**BottomNavigation** - [x] native implementation [Android] - [x] nesting navigations - [x] load one view at a time - [x] TabStrip declaration - [x] Angular support **Tabs** - [x] native implementation [iOS] - [x] nesting navigations - [x] pre-load one view to the sides by default - [x] TabStrip declaration - [x] offscreenTabLimit - [x] tabsPosition - [x] swipeEnabled - [x] Angular support **TabStrip** - [x] CSS background-color **TabStripItem** - [x] CSS pseudo class :active - [x] CSS background-color - [x] CSS color - [x] CSS font - [x] CSS font-size - [x] CSS highlight-color - [x] CSS text-transform - [x] iconSource font-icon support - [x] Image instead of iconSource declaration - [x] Label instead of title declaration Issues: - [x] [iOS Tabs] Tap on tabs does not change item - NativeScript/NativeScript#7435 - [x] [iOS Tabs] Tabs icons does not work - NativeScript/NativeScript#7436 - [x] [iOS Tabs] A crash on swiping a content item - NativeScript/NativeScript#7459 - [x] [BottomNavigation]: crash when navigating without transition animation - NativeScript/NativeScript#7481 - [ ] [BottomNavigation] - crash when used with nativescript-advanced-webview https://github.com/NativeScript/NativeScript/issues/7901 - [ ] [iOS][BottomNavigation] Images are not vertically centered - https://github.com/NativeScript/NativeScript/issues/7991 - [ ] [BottomNavigation] Calling js method onSelectedPositionChange failed - https://github.com/NativeScript/NativeScript/issues/8057
NativeScript 6.1 (components released as OFFICIAL)
**BottomNavigation** - [x] Vue.js support - [x] No TabStrip support (tabBarVisibility/no declaration) - [x] limit bar to 5 tabs **Tabs** - [x] Vue.js support - [x] safe area improvements - [x] No TabStrip support (tabBarVisibility/no declaration) **TabStrip** - [x] itemTap event: https://github.com/NativeScript/NativeScript/pull/7711 **TabStripItem** - [x] tap event: https://github.com/NativeScript/NativeScript/pull/7693 - [x] Label title CSS support - [x] Image icon CSS support Issues: - [x] [Tabs][Android] unable to select over one or more TabStripItem NativeScript/NativeScript#7519 - [x] [BottomNavigation][Android]: crash when selecting tab with no correspondent item https://github.com/NativeScript/NativeScript/issues/7526 - [x] [Tabs][iOS] Incorrect tab bar when Tabs are wrapped in any layout - https://github.com/NativeScript/NativeScript/issues/7531 - [x] [iOS][Tabs] Unable to return to tab after tab with nested frame visited https://github.com/NativeScript/NativeScript/issues/7564 - [x] [BottomNavigation][iOS] created dynamically does not shows the TabStrip - NativeScript/NativeScript#7433 - [x] [Tabs][Android] TabStripItem selection highlight not visible with TabStripItem background color set - NativeScript/NativeScript#7494 - [x] [Tabs] TabStripItem color not applied - NativeScript/NativeScript#7495 - [x] [Tabs] Cannot change active text color for selected tabstripitem - NativeScript/NativeScript#7507 - [x] [BottomNav][Android] Changing tabs messes up text color of tabs - NativeScript/NativeScript#7623 - [x] [Tabs][BottomNavigation] TabContentItem background color not applied - NativeScript/NativeScript#7496 - [x] [Tabs][BottomNavigation] Font icon does not update to active state for selected tabstripitem - NativeScript/NativeScript#7506 - [x] [BottomNavigation] Renders bottom empty space if tabstrip is not defined - NativeScript/NativeScript#7471 - [x] [BottomNavigation][Tabs][iOS] TabStripItem font icon doesn't apply own classes - https://github.com/NativeScript/NativeScript/issues/7547 - [x] [iOS][Tabs][BottomNavigation] TabStrip.iosIconRenderingMode property value not respected https://github.com/NativeScript/NativeScript/issues/7733 - [x] [iOS][Tabs][BottomNavigation] Crash with TabStrip configured in code-behind https://github.com/NativeScript/NativeScript/issues/7692 - [x] [BottomNav] Clipped tabstripitem title content when iconSource specified https://github.com/NativeScript/NativeScript/issues/7713 Angular - [x] [Tabs] TabStripItem does not render - NativeScript/nativescript-angular#1884 - [x] [BottomNavigation] TabStripItem does not render - NativeScript/nativescript-angular#1893 - [x] Angular binding inside selectedIndexChanged event would work only if wrapped in NgZone - NativeScript/nativescript-angular#1896
Issues:
BottomNavigation
Tabs
TabBars
Issues:
If you want to work on a task from the list, tell us and we will do our best to help you!
If you have another great idea on how to make the tab view even cooler, share it in the comments!
Please, don't report problems here. Instead, open a new issue and link it to this one.
Let's use this discussion for suggestions and improvement ideas. We would love to hear from you!
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
I expect ability to use FormattedString
for TabStripItem
. I think TabStripItem
should extend TextBase
. This would give full control over how it should look (because it behaves essentially like a Button
).
I do not feel any special advantages over what was before.
For example, I need combine icon font, with formatted text in tab title.
@webleaf Unfortunately, customization options are greatly limited by the underlying native implementations. For example, on iOS the BottomNavigation
TabStripItem
is not even a UIView
, so we can't really make it a TextBase
. What we can do though, is provide the option to remove the bar and let you create your own bar with layouts and text views and animations and everything. Check out the PR - https://github.com/NativeScript/NativeScript/pull/7580. There is an example there. Will this work for you?
Hi guys,
I have a plugin nativescript-bottom-navigation based on material components
that would be part of nativescript-material-components
and I'm wondering if my plugin will give you issues because I'm registering the component as BottomNavigation
for angular and in some projects the error below is appearing and another issue that already was addressed here
ERROR in ../node_modules/nativescript-angular/element-registry.js
Module not found: Error: Can't resolve 'tns-core-modules/ui/bottom-navigation' in 'BugRepo\node_modules\nativescript-angular'
@ ../node_modules/nativescript-angular/element-registry.js 142:57-105
@ ../node_modules/nativescript-angular/renderer.js
@ ../node_modules/nativescript-angular/nativescript.module.js
@ ./app/app.module.ts
@ ./main.ts
Hi @henrychavez
This is a known error that occurs when you use a certain newer version of nativescript-angular
and version pre 6.0 of the tns-core-modules
. Either update nativescript-angular
to the latest patch or update tns-core-modules
to 6.0. The problem should go away.
There shouldn't be a problem with clashing names. You should be able to override the core modules elements. Both nativescript-angular
and nativescript-vue
should support overriding of registered elements, so the last one wins.
That being said, I think there actually might be a problem with your plugin's name and its functionality. From your code I see that you are exposing BottomNavigationBar
components as in, only the bar, not the whole navigation component. It's a bit confusing, but the material guidelines declare BottomNavigation
and Tabs
more as patterns whereas the components are the MDCBottomNavigationBar
and MDCTabBar
. I'm saying this because for 6.1 we will expose the ability to use BottomNavigation
, but remove the default bar and use your own - see https://github.com/NativeScript/NativeScript/pull/7580. If you keep the element name BottomNavigation
for your plugin, it will override the core modules one and this won't be possible. If you rename it to BottomNavigationBar
you will be able to combine the two and achieve more :) Let me know your thoughts.
Hi @MartoYankov,
I agree with you the docs are a little confusing related to BottomNavigation
and Tabs
that the material design team describe in their documentation.
I just review the code for bottom-navigation
that you guys are doing and you are right, is better if I rename the plugin to BottomNavigationBar
because I'm just exposing the component and leaving the implementation of navigation to the developer and you guys are preparing a more complete solution.
I like the possibility to combine both, so in that way, the developer can use the bottom-navigation-bar
that fits their needs (you have a custom bar to support fonts and custom items, something that can't be done using the BottomNavigationView
or MDCBottomNavigationBar
provided by material components) that being said, the developer can use my plugin if they want to use what the material components provide us or your implementation of the bottom-navigation-bar
if they want something more custom, am I right? :D
Hey @MartoYankov
When will this be a part of the tab template when we are creating a new app with tns create
command? (It generates the template with the old TabView atm)
@vahidvdn Tab template should start generating app with BottomNavigation component for NativeScript 6.1 in September -- the changes are currently on PR https://github.com/NativeScript/nativescript-app-templates/pull/79
Is it expected that on iOS placing tabs inside some other element breaks the view ?
I am using old TabView for general navigation, and now in one of my pages i want to have another tabview ( inside a CardView ), I have used new Tabs item. It looks good(ish) on android but totally doesn't work on iOS - is the scenario i'm trying to achieve possible or it is expected to be impossible ? Same code produces following results on both platforms ( left iOS, right Android )
@michalMajkel This is an interesting scenario. Can you try nesting the Tabs
component in a layout. See this article about nesting - https://docs.nativescript.org/core-concepts/nested-navigation#simple-rule
Question: Is there a way to not preload tabs at all? Essentially setting the offscreenTabLimit
to zero?. This would cause issues with swipe, but that could be disabled as well.
Possible use case would be providing three different views and subsequent actions based off the same data where by the data might be a different state that would cause it to show up in only one tab at a time.
For example. I have a list of Appointments and I'd like to have them show up in 3 tabs: Requested, Responded and Scheduled.
As it stands right now with a custom Tab UI implementation, when I load a tab, I go to the database and load the data. The query to the database prefiltrs the data so that it only brings the data it needs into the specific tab. I realize there are a lot of different ways I can do this, but this is the pattern being used and I wondered if it was possible to continue with the pattern.
The alternative is to load all the data in the parent tabs view, hold it somewhere and then have the specific tabs filter the data as we transition between them. This will work fine for us in our situation, but there might be a use case for someone else where this pattern doesn't work and they'd like to keep the database queries on a per tab basis.
@jawa-the-hutt In short, you should use the BottomNavigation
component. It doesn't pre-load tabs. Do you have an issue with it?
Otherwise, we tried disabling pre-load with the old TabView
component. On Android it's not possible to tell the ViewPager to not pre-load tabs. We did a hacky workaround that proved to bring lots of bugs and problems.
This is part of the reason why we decided to split the tab navigation. The BottomNavigation
component doesn't pre-load and doesn't have a swipe gesture. The Tabs
pre-loads at least one tab to the sides and has the swipe gesture. Both have their use cases. We ultimately decided they can't be combined in one component safely.
@MartoYankov. Thanks for the info. My use case calls for the Tabs to be just below the header in the app and not at the bottom. So...in a perfect world, I'd have the functionality of the bottom navigation, but be able to position it vertically wherever I wanted in the UI.
However, I do understand having to deal with the limitations of what the native platforms give us.
@jawa-the-hutt The way I understand it the reason why the BottomNavigation
bar is on the bottom is that when you don't have the swipe gesture it's hard to reach to the top with your thumb to navigate.
That being said, the scenario you want should be possible with the BottomNavigation
without (with a hidden) a TabStrip
and use a custom tab bar on top. There are also a couple of plugins that provide tab bars that you can position anywhere.
@MartoYankov I wanted to follow back up on something in one of your comments above. You mentioned that the BottomNavigation
component doesn't pre-load tabs. I'm finding that it does preload tabs. I can create a new issue if this is a bug, but first I wanted to make sure I understood you correctly.
What i'm seeing is that each tab is pre-loading. I'm using a simple console.log
inside the Vue created
lifecycle and each of those are logging at app startup. Here's a link to a playground.
@jawa-the-hutt Vue (and Angular or any other framework for that matter) components have their own lifecycle that the native components don't affect. If you use the loaded
event on each TabContentItem
or on a element in the separate components, you will see when the UI is loaded on the native side.
Is there any plans to make it easy to change the tab highlight color ?
I ended up figuring out to do it after looking into the code, but I would expect it to be doable in css
current code:
<Tabs (loaded)="tabsViewLoaded($event)">
tabsViewLoaded(event) {
const tabs: Tabs = event.object;
tabs.setTabBarHighlightColor(new Color('rgb(81, 174, 88)'));
}
I'm feeling really frustrated with this. Label and Image CSS Styling is checked off for 6.1 but it seems really broken still on 6.1.2. And TabView completely breaks my app, so I'm kind of out of options.
@AnthonyLenglet Yes, there is a highlight-color
property on the TabStrip
element. You can use it in CSS. It seems we failed to document it. Will fix this.
@jlafitte Can you elaborate more on what you wanted to achieve, but couldn't? The TabStrip Label and Image styling is limited by the native components underneath. You can style background-color, color, font and text-transform. This brings feature parity with the styling of TabView.
Have to agree with @jlafitte . At least for iOS building with XCode11/iOS13 the control styling seems buggier than it was with 6.0. Far from my understanding of a RC release let alone an official release.
@PeterStaev It seems iOS 13 brought lots of breaking/behavior changes to lots of UIKit components. There are also problems with XCode11/iOS13 with our testing infrastructure too, which is the reason we couldn't extensively test everything. We are receiving increasing issue reports about this and we're aware of it. It's not connected to the BottomNav/Tabs components only.
Thanks @MartoYankov. Leave it to Apple/Google to mess up the things... 馃槃 I guess I will see to downgrade to XCode 10.3 and hope that Apple review wont deny the app release for not targeting iOS13 馃槣
I want to change tab indicator (bottom line) height (for android), how I can do that? Can someone please help me.
Thanks @felix-idf! But I mean the height(weight) of line, not a color :)
@AtoianAvetik This isn't supported at the moment. You can open a feature request for it.
@AtoianAvetik
TabStrip{ highlight-color: red; }
They have updated the docs here
it dont work
@mkrierQape Here is a playground link from the blog post - https://play.nativescript.org/?template=play-tsc&id=hhPr9s . The highlight color is changed to white.
Issue related nested routing on BottomNavigation using nativescript-angular
Navigation structure according this structure:
const routes: Routes = [
{ path: "welcome", component: WelcomeComponent },
{ path: "pages", loadChildren: () => import("./pages/pages.module").then(m => m.PagesModule) },
{ path: "", redirectTo: "welcome", pathMatch: "full" },
];
const routes: Routes = [
{
path: '',
component: PagesComponent,
children: [
{
path: 'home',
outlet: 'homeoutlet',
component: HomeComponent
},
{
path: 'advices',
outlet: 'advicesoutlet',
component: AdvicesComponent
},
{
path: 'alerts',
outlet: 'alertsoutlet',
component: AlertsComponent
},
{ path: '', redirectTo: '/(homeoutlet:home//advicesoutlet:advices//alertsoutlet:alerts)', pathMatch: 'prefix' }
]
}
];
When i am trying to navigate from /welcome route to pages/[path] route,
this.routerExtensions.navigate([{ outlets: { homeoutlet: ['pages', 'home'] } }]);
i get this error:
Error: ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'pages/home'
Playground example: https://play.nativescript.org/?template=play-ng&id=sVR895&v=3
@smorcuend
The path:''
shouldn't be empty when you use named outlet in your pages-routing.module.ts
.
Just try path:'default'
to have the outlet find the activeRoute
.
Thanks
Just curios, is someone still working on the open issues? Or is the list outdated?
Most helpful comment
@jawa-the-hutt In short, you should use the
BottomNavigation
component. It doesn't pre-load tabs. Do you have an issue with it?Otherwise, we tried disabling pre-load with the old
TabView
component. On Android it's not possible to tell the ViewPager to not pre-load tabs. We did a hacky workaround that proved to bring lots of bugs and problems.This is part of the reason why we decided to split the tab navigation. The
BottomNavigation
component doesn't pre-load and doesn't have a swipe gesture. TheTabs
pre-loads at least one tab to the sides and has the swipe gesture. Both have their use cases. We ultimately decided they can't be combined in one component safely.