Switching between tabs, that are one or more inner/sibling view deep, breaks navigation

When using tabs in Ionic Vue, the navigation breaks when you switch between tabs if two or more tabs are one or more inner/sibling view deep in their respective navigation stacks.

This might be due to the incorrect use of tabs on my end, but the issue is consistently re-creatable on a fresh Ionic Vue project with tabs.

Steps to re-produce

  1. Start the app on the first tab.
  2. Open the first tab’s inner/sibling view.
  3. Switch to a second tab.
  4. Open the second tab’s inner/sibling view.
  5. Switch back to the first tab.
  6. Use the tab button or a <ion-back-button> to navigate back to this tab’s root page.
  7. Switch back to the second tab again.
  8. Trying to go back to the initial page on this tab, either by tapping the tab button again or using a <ion-back-button>, breaks navigation.

This also happens if you have, say 4 or 5 tabs, and switch between them normally like you would any other app if at least two of those tabs are one inner/sibling view deep.

Obviously, this is a pretty strange issue and will probably not occur in a production app often, if ever.

Also, I’ve noticed that if the navigation breaks on a physical device, it sometime causes the app to crash and restart from the splash screen.

I would appreciate any advice or pointers on this if I’m using tabs incorrectly.

StackBlitz
https://stackblitz.com/~/github.com/EA-Wardie/ionic-tabs-vue

Code

TabsPage.vue (generated with ionic start)

<template>
  <ion-page>
    <ion-tabs>
      <ion-router-outlet></ion-router-outlet>
      <ion-tab-bar slot="bottom">
        <ion-tab-button tab="tab1" href="/tabs/tab1">
          <ion-icon aria-hidden="true" :icon="triangle" />
          <ion-label>Tab 1</ion-label>
        </ion-tab-button>

        <ion-tab-button tab="tab2" href="/tabs/tab2">
          <ion-icon aria-hidden="true" :icon="ellipse" />
          <ion-label>Tab 2</ion-label>
        </ion-tab-button>

        <ion-tab-button tab="tab3" href="/tabs/tab3">
          <ion-icon aria-hidden="true" :icon="square" />
          <ion-label>Tab 3</ion-label>
        </ion-tab-button>
      </ion-tab-bar>
    </ion-tabs>
  </ion-page>
</template>

Tab1Page.vue (generated with minor changes)

<template>
    <ion-page>
        <ion-header>
            <ion-toolbar>
                <ion-title>Tab 1</ion-title>
            </ion-toolbar>
        </ion-header>
        <ion-content :fullscreen="true">
            <ion-button router-link="/tabs/tab1/view">Go To Inner View</ion-button>
        </ion-content>
    </ion-page>
</template>

Tab1View.vue (inner view created for tab 1)

<template>
    <ion-page>
        <ion-header>
            <ion-toolbar>
                <ion-buttons slot="start">
                    <ion-back-button/>
                </ion-buttons>
                <ion-title>Inner Tab 1 View</ion-title>
            </ion-toolbar>
        </ion-header>

        <ion-content fullscreen color="light">
            Inner Tab 1 View
        </ion-content>
    </ion-page>
</template>

Tab2Page.vue (generated with minor changes)

<template>
    <ion-page>
        <ion-header>
            <ion-toolbar>
                <ion-title>Tab 2</ion-title>
            </ion-toolbar>
        </ion-header>
        <ion-content :fullscreen="true">
            <ion-button router-link="/tabs/tab2/view">Go To Inner View</ion-button>
        </ion-content>
    </ion-page>
</template>

Tab2View.vue (inner view created for tab 2)

<template>
    <ion-page>
        <ion-header>
            <ion-toolbar>
                <ion-buttons slot="start">
                    <ion-back-button/>
                </ion-buttons>
                <ion-title>Inner Tab 2 View</ion-title>
            </ion-toolbar>
        </ion-header>

        <ion-content fullscreen color="light">
            Inner Tab 2 View
        </ion-content>
    </ion-page>
</template>

index.ts (routes)

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    redirect: '/tabs/tab1'
  },
  {
    path: '/tabs/',
    component: TabsPage,
    children: [
      {
        path: '',
        redirect: '/tabs/tab1'
      },
      {
        path: 'tab1',
        component: () => import('@/views/Tab1Page.vue')
      },
      {
        path: 'tab1/view',
        component: () => import('@/views/Tab1View.vue'),
      },
      {
        path: 'tab2',
        component: () => import('@/views/Tab2Page.vue')
      },
      {
        path: 'tab2/view',
        component: () => import('@/views/Tab2View.vue'),
      },
      {
        path: 'tab3',
        component: () => import('@/views/Tab3Page.vue')
      },
    ]
  }
]

You shouldn’t be using child routes within tabs but instead sibling routes. See Child Routes within Tabs.

Might want to also read about Shared URLs vs. Nested Routes too.

Thanks for the reply.

I think I used the wrong term. Based on my routes code example, I am using sibling routes as described in the docs (I’ll update the post accordingly). Unless I’m misunderstanding something?

Oh my bad. I read the documentation wrong :grimacing: It is showing a sibling within the children for the tabs.

It would be helpful if you could create a StackBlitz or repo that reproduces the issue so we can easily run it and see the issue.

Here’s a StackBlitz.

https://stackblitz.com/~/github.com/EA-Wardie/ionic-tabs-vue

I tested it out and had it where hitting the IonBackButton wouldn’t do anything (the navigation broke). Doesn’t seem to be consistent though following your steps.

I would guess it is an obscure bug in Ionic. Have you searched open issues? Maybe create a bug report? Otherwise, hopefully someone else can chime in.

1 Like

Thanks for taking the time and checking it out.

The more I’ve been looking at the issue, I realised my steps are unnecessarily complicated. Basically, as long as at least two tabs are one sibling page deep, using the back functionality in one of them, breaks the back functionality in the other.

But I’ll check the open issues or open a bug report if I don’t find anything.

Thanks again :slight_smile:

It should work as each tab has its own navigation stack.

Each tab in Ionic is treated as an individual navigation stack. This means if you have three tabs in your application, each tab has its own navigation stack. Within each stack you can navigate forwards (push a view) and backwards (pop a view). (source)

There are some comments in the source for handleNavigateBack which is used by IonBackButton.

1 Like

Defiantly also how I understand the docs.

I think I’ve found an open issue that sounds very similar to what I’m experiencing.

Thanks for linking the source and comments. Helps to better understand what’s happening.
Also helps to definitively know that router.back() with useIonRouter() does actually navigate back linearly. This had me pretty confused when router.back() started programmatically switching tabs (which the docs point out shouldn’t be done).

I’ve also started experimenting with only routing the bottom level tabs and other linear pages, and instead using <ion-nav> and <ion-nav-link> for tab sibling/child pages. It does fix the broken navigation issue, since tab siblings/children aren’t navigating with routes this way.

However, this also stops the tabs from navigating views back internally. This can probably be achieved with some custom code, but that does sound a bit hacky since the docs clearly state <ion-nav> shouldn’t be used to replace routing.

1 Like