{"record":{"id":"b91d7456be7f2b43","repo":"ionic-team/ionic-framework","slug":"iontabs-cannot-contain-an-ionrouteroutlet-and-iont","errorCode":null,"errorMessage":"IonTabs cannot contain an IonRouterOutlet and IonTab at the same time.","messagePattern":"IonTabs cannot contain an IonRouterOutlet and IonTab at the same time\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vue/src/components/IonTabs.ts","lineNumber":144,"sourceCode":"      routerOutlet = slottedContent.find((child: VNode) =>\n        isRouterOutlet(child)\n      );\n\n      /**\n       * Developers must pass at least one ion-tab\n       * inside of ion-tabs if they want to use a\n       * basic tab-based navigation without the\n       * history stack or URL updates associated\n       * with the router.\n       */\n      hasTab = slottedContent.some((child: VNode) => isTab(child));\n    }\n\n    if (!routerOutlet && !hasTab) {\n      throw new Error(\"IonTabs must contain an IonRouterOutlet or an IonTab.\");\n    }\n    if (routerOutlet && hasTab) {\n      throw new Error(\n        \"IonTabs cannot contain an IonRouterOutlet and IonTab at the same time.\"\n      );\n    }\n\n    if (hasTab) {\n      return h(\n        \"ion-tabs\",\n        {\n          ...props,\n        },\n        slottedContent\n      );\n    }\n\n    /**\n     * TODO(ROU-11056)\n     *\n     * Vue handles the error case for when there is no","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/ionic-team/ionic-framework/blob/625f9c38ad8c5db8a6c12df5c1622a36da90f9e3/packages/vue/src/components/IonTabs.ts#L126-L162","documentation":"Thrown from Vue `<IonTabs>` render() when the slot contains BOTH an `IonRouterOutlet` and an `IonTab`. These are mutually exclusive navigation models: IonTabs must use either the router outlet (URL/history-based) OR plain `IonTab` children (router-less), never both. The check exists to prevent ambiguous tab state.","triggerScenarios":"Authoring `<IonTabs>` that simultaneously includes `<IonRouterOutlet>` (or `ion-router-outlet`) and one or more `<IonTab>` (`ion-tab`) descendants anywhere in the slotted VNodes, including inside a Fragment/v-for.","commonSituations":"Partially migrating from router-less tabs to router tabs and leaving an `<IonTab>` behind; combining a router outlet with manually-declared tab children in the same template; tabs generated from a list where both shapes are present.","solutions":["Pick one navigation model: keep `<IonRouterOutlet>` and remove all `<IonTab>` children, OR keep `<IonTab>` children and remove the outlet.","Search the `<IonTabs>` template for `IonTab`/`ion-tab` and `IonRouterOutlet`/`ion-router-outlet` and remove the unwanted one.","If using router-less tabs, drive tab content via `<IonTab>` components and an `<IonTabBar>` without an outlet.","If using router tabs, declare routes inside `<IonRouterOutlet>` and do not author `<IonTab>` elements."],"exampleFix":"<!-- before (both present) -->\n<IonTabs>\n  <IonRouterOutlet>...</IonRouterOutlet>\n  <IonTab tab=\"home\">...</IonTab>\n</IonTabs>\n<!-- after (router model only) -->\n<IonTabs>\n  <IonRouterOutlet>...</IonRouterOutlet>\n  <IonTabBar slot=\"bottom\">...</IonTabBar>\n</IonTabs>","handlingStrategy":"type-guard","validationCode":"const outlet = slotted?.some((n) => n?.type && ((n.type as any).name === 'IonRouterOutlet' || n.type === 'ion-router-outlet'));\nconst tab = slotted?.some((n) => n?.type && ((n.type as any).name === 'ion-tab' || n.type === 'IonTab'));\nif (outlet && tab) {\n  throw new Error('Choose one: IonRouterOutlet (router tabs) OR IonTab (router-less tabs), not both.');\n}","typeGuard":"function isExclusiveTabsModel(slotted: any[] | undefined): boolean {\n  const outlet = !!slotted?.some((n) => n?.type && ((n.type as any).name === 'IonRouterOutlet' || n.type === 'ion-router-outlet'));\n  const tab = !!slotted?.some((n) => n?.type && ((n.type as any).name === 'ion-tab' || n.type === 'IonTab'));\n  return outlet !== tab; // true only when exactly one is present\n}","tryCatchPattern":null,"preventionTips":["Decide the tab navigation model up front and keep templates consistent.","During migration, remove the old shape when adding the new one.","Code-review tab templates for any leftover IonTab or IonRouterOutlet."],"tags":["vue","ion-tabs","navigation","render"],"backgroundTag":null,"analyzedSha":"625f9c38ad8c5db8a6c12df5c1622a36da90f9e3","analyzedAt":"2026-08-12T16:00:25.413Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}