{"record":{"id":"379a9fc4aa2a319a","repo":"ionic-team/ionic-framework","slug":"iontabs-cannot-contain-an-ionrouteroutlet-and-an-i","errorCode":null,"errorMessage":"IonTabs cannot contain an IonRouterOutlet and an IonTab at the same time","messagePattern":"IonTabs cannot contain an IonRouterOutlet and an IonTab at the same time","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react/src/components/navigation/IonTabs.tsx","lineNumber":181,"sourceCode":"          onIonTabsDidChange,\n        };\n      }\n\n      if (onIonTabsWillChange !== undefined) {\n        childProps = {\n          ...childProps,\n          onIonTabsWillChange,\n        };\n      }\n\n      this.ionTabContextState.tabBarProps = childProps;\n    });\n\n    if (!outlet && !hasTab) {\n      throw new Error('IonTabs must contain an IonRouterOutlet or an IonTab');\n    }\n    if (outlet && hasTab) {\n      throw new Error('IonTabs cannot contain an IonRouterOutlet and an IonTab at the same time');\n    }\n\n    if (hasTab) {\n      return <IonTabsInner {...this.props}></IonTabsInner>;\n    }\n\n    /**\n     * TODO(ROU-11051)\n     *\n     * There is no error handling for the case where there\n     * is no associated Route for the given IonTabButton.\n     *\n     * More investigation is needed to determine how to\n     * handle this to prevent any overwriting of the\n     * IonTabButton's onClick handler and how the routing\n     * is handled.\n     */\n","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/ionic-team/ionic-framework/blob/625f9c38ad8c5db8a6c12df5c1622a36da90f9e3/packages/react/src/components/navigation/IonTabs.tsx#L163-L199","documentation":"Thrown during React `<IonTabs>` render when children contain BOTH an `IonRouterOutlet` (by type or `isRouterOutlet`) and an `IonTab`. The two are mutually exclusive navigation models; the component rejects the combination to avoid ambiguous tab state and broken routing.","triggerScenarios":"Authoring `<IonTabs>` with both `<IonRouterOutlet>` and one or more `<IonTab>` components among the children (directly or inside a fragment whose first child is an outlet).","commonSituations":"Mid-migration between router-less and router-based tabs leaving both shapes in place; copy-pasting tab snippets that mix patterns; rendering tabs from a list where both an outlet and tab elements are present.","solutions":["Choose one model: keep `<IonRouterOutlet>` and remove all `<IonTab>` children, or keep `<IonTab>` children and remove the outlet.","Search the `<IonTabs>` subtree for `IonRouterOutlet` and `IonTab` and remove the unwanted one.","For router-less tabs use `<IonTab>` + `<IonTabBar>` without an outlet.","For router tabs use `<IonRouterOutlet>` + `<Route>` and do not declare `<IonTab>` elements."],"exampleFix":"// before (both present)\n<IonTabs>\n  <IonRouterOutlet><Route path=\"/home\" component={Home} /></IonRouterOutlet>\n  <IonTab tab=\"home\"><Home /></IonTab>\n</IonTabs>\n// after (router model only)\n<IonTabs>\n  <IonRouterOutlet><Route path=\"/home\" component={Home} /></IonRouterOutlet>\n  <IonTabBar slot=\"bottom\"><IonTabButton tab=\"home\" href=\"/home\"><IonLabel>Home</IonLabel></IonTabButton></IonTabBar>\n</IonTabs>","handlingStrategy":"validation","validationCode":"let outlet = false, hasTab = false;\nReact.Children.forEach(children, (child: any) => {\n  if (child?.type === IonRouterOutlet || child?.type?.isRouterOutlet) outlet = true;\n  else if (child?.type === IonTab) hasTab = true;\n});\nif (outlet && hasTab) {\n  throw new Error('Choose one: IonRouterOutlet (router tabs) OR IonTab (router-less tabs).');\n}","typeGuard":"function isExclusiveTabsModel(children: React.ReactNode): boolean {\n  let outlet = false, hasTab = false;\n  React.Children.forEach(children, (child: any) => {\n    if (child?.type === IonRouterOutlet || child?.type?.isRouterOutlet) outlet = true;\n    else if (child?.type === IonTab) hasTab = true;\n  });\n  return outlet !== hasTab;\n}","tryCatchPattern":null,"preventionTips":["Pick one tabs navigation model and remove the other shape during migration.","Review tab templates for stray IonTab or IonRouterOutlet elements.","Keep router-less and router tab examples separate to avoid mixing."],"tags":["react","ion-tabs","navigation","render"],"backgroundTag":null,"analyzedSha":"625f9c38ad8c5db8a6c12df5c1622a36da90f9e3","analyzedAt":"2026-08-12T16:00:25.413Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}