diff --git a/packages/vue/src/components/IonTabs.ts b/packages/vue/src/components/IonTabs.ts
index d4f9dac129..d519cc02ff 100644
--- a/packages/vue/src/components/IonTabs.ts
+++ b/packages/vue/src/components/IonTabs.ts
@@ -7,9 +7,22 @@ const DID_CHANGE = 'ionTabsDidChange';
export const IonTabs = /*@__PURE__*/ defineComponent({
name: 'IonTabs',
emits: [WILL_CHANGE, DID_CHANGE],
+ data() {
+ return { didWarn: false }
+ },
render() {
- const { $slots: slots, $emit } = this;
+ const { $slots: slots, $emit, $data } = this;
const slottedContent = slots.default && slots.default();
+ let userProvidedRouterOutlet;
+
+ if (slottedContent && slottedContent.length > 0) {
+ /**
+ * If developer passed in their own ion-router-outlet
+ * instance, then we should not init a default one
+ */
+ userProvidedRouterOutlet = slottedContent.find((child: VNode) => child.type && (child.type as any).name === 'IonRouterOutlet');
+ }
+
let childrenToRender = [
h('div', {
class: 'tabs-inner',
@@ -18,18 +31,52 @@ export const IonTabs = /*@__PURE__*/ defineComponent({
'flex': '1',
'contain': 'layout size style'
}
- }, [
- h(IonRouterOutlet)
- ])
+ }, (userProvidedRouterOutlet) ? userProvidedRouterOutlet : [h(IonRouterOutlet)])
];
+ if (userProvidedRouterOutlet && !$data.didWarn) {
+ console.warn(`[@ionic/vue Deprecation] Starting in Ionic Vue v6.0, developers must add an 'ion-router-outlet' instance inside of 'ion-tabs'.
+
+ Before:
+
+
+
+ ...
+
+
+
+ After:
+
+
+
+
+ ...
+
+
+
+ Be sure to import 'IonRouterOutlet' from '@ionic/vue' and provide that import to your Vue component. See https://ionicframework.com/docs/vue/navigation#working-with-tabs for more information.
+ `);
+
+ $data.didWarn = true;
+ }
+
/**
* If ion-tab-bar has slot="top" it needs to be
* rendered before `.tabs-inner` otherwise it will
* not show above the tab content.
*/
if (slottedContent && slottedContent.length > 0) {
- const slottedTabBar = slottedContent.find((child: VNode) => child.type && (child.type as any).name === 'IonTabBar');
+
+ /**
+ * Render all content except for router outlet
+ * since that needs to be inside of `.tabs-inner`.
+ */
+ const filteredContent = slottedContent.filter((child: VNode) => (
+ !child.type ||
+ (child.type && (child.type as any).name !== 'IonRouterOutlet')
+ ));
+
+ const slottedTabBar = filteredContent.find((child: VNode) => child.type && (child.type as any).name === 'IonTabBar');
const hasTopSlotTabBar = slottedTabBar && slottedTabBar.props?.slot === 'top';
if (slottedTabBar) {
@@ -49,13 +96,13 @@ export const IonTabs = /*@__PURE__*/ defineComponent({
if (hasTopSlotTabBar) {
childrenToRender = [
- ...slottedContent,
+ ...filteredContent,
...childrenToRender
];
} else {
childrenToRender = [
...childrenToRender,
- ...slottedContent
+ ...filteredContent
]
}
}
diff --git a/packages/vue/src/components/Overlays.ts b/packages/vue/src/components/Overlays.ts
index a63d903066..1279d8839f 100644
--- a/packages/vue/src/components/Overlays.ts
+++ b/packages/vue/src/components/Overlays.ts
@@ -18,11 +18,12 @@ import { IonToast as IonToastCmp } from '@ionic/core/components/ion-toast.js'
import { defineOverlayContainer } from '../vue-component-lib/overlays';
export const IonActionSheet = /*@__PURE__*/ defineOverlayContainer('ion-action-sheet', IonActionSheetCmp, ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'keyboardClose', 'leaveAnimation', 'mode', 'subHeader', 'translucent'], actionSheetController);
-
+
export const IonAlert = /*@__PURE__*/ defineOverlayContainer('ion-alert', IonAlertCmp, ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'inputs', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'subHeader', 'translucent'], alertController);
-
+
export const IonLoading = /*@__PURE__*/ defineOverlayContainer('ion-loading', IonLoadingCmp, ['animated', 'backdropDismiss', 'cssClass', 'duration', 'enterAnimation', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'showBackdrop', 'spinner', 'translucent'], loadingController);
-
+
export const IonPicker = /*@__PURE__*/ defineOverlayContainer('ion-picker', IonPickerCmp, ['animated', 'backdropDismiss', 'buttons', 'columns', 'cssClass', 'duration', 'enterAnimation', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop'], pickerController);
-
+
export const IonToast = /*@__PURE__*/ defineOverlayContainer('ion-toast', IonToastCmp, ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'position', 'translucent'], toastController);
+
diff --git a/packages/vue/test-app/src/views/TabsNew.vue b/packages/vue/test-app/src/views/TabsNew.vue
new file mode 100644
index 0000000000..9d4c4fff3a
--- /dev/null
+++ b/packages/vue/test-app/src/views/TabsNew.vue
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+ Tab {{ tab.id }}
+
+
+ Add Tab
+
+
+
+
+
+
+