diff --git a/packages/react-router/test-app/cypress/integration/dynamic-ionpage-classnames.js b/packages/react-router/test-app/cypress/integration/dynamic-ionpage-classnames.js
new file mode 100644
index 0000000000..d41781fe21
--- /dev/null
+++ b/packages/react-router/test-app/cypress/integration/dynamic-ionpage-classnames.js
@@ -0,0 +1,18 @@
+const port = 3000;
+
+describe('Dynamic IonPage Classnames', () => {
+ /*
+ This spec tests that classnames can be added to IonPages dynamically and that the IonPage
+ doesn't get ion-page-invisible added back to it when it does change
+ Fixes bug reported in https://github.com/ionic-team/ionic-framework/issues/22631
+ */
+
+ it('/dynamic-ionpage-classnames, when a class is added to an IonPage, the class should be applied to the element and the page should still be visible', () => {
+ cy.visit(`http://localhost:${port}/dynamic-ionpage-classnames`);
+ cy.ionPageVisible('dynamic-ionpage-classnames');
+ cy.get('.initial-class');
+ cy.contains('Add Class').click();
+ cy.get('.other-class');
+ cy.ionPageVisible('dynamic-ionpage-classnames');
+ });
+});
diff --git a/packages/react-router/test-app/src/App.tsx b/packages/react-router/test-app/src/App.tsx
index 16ded6277b..75ef0f0398 100644
--- a/packages/react-router/test-app/src/App.tsx
+++ b/packages/react-router/test-app/src/App.tsx
@@ -33,6 +33,7 @@ import TabsContext from './pages/tab-context/TabContext';
import { OutletRef } from './pages/outlet-ref/OutletRef';
import { SwipeToGoBack } from './pages/swipe-to-go-back/SwipToGoBack';
import Refs from './pages/refs/Refs';
+import DynamicIonpageClassnames from './pages/dynamic-ionpage-classnames/DynamicIonpageClassnames';
debugger;
const App: React.FC = () => {
return (
@@ -49,6 +50,7 @@ const App: React.FC = () => {
+
diff --git a/packages/react-router/test-app/src/pages/Main.tsx b/packages/react-router/test-app/src/pages/Main.tsx
index 75b67f711a..6075da45f5 100644
--- a/packages/react-router/test-app/src/pages/Main.tsx
+++ b/packages/react-router/test-app/src/pages/Main.tsx
@@ -52,6 +52,9 @@ const Main: React.FC = () => {
Swipe to go back
+
+ Dynamic IonPage Classnames
+
Refs
diff --git a/packages/react-router/test-app/src/pages/dynamic-ionpage-classnames/DynamicIonpageClassnames.tsx b/packages/react-router/test-app/src/pages/dynamic-ionpage-classnames/DynamicIonpageClassnames.tsx
new file mode 100644
index 0000000000..baba236a0c
--- /dev/null
+++ b/packages/react-router/test-app/src/pages/dynamic-ionpage-classnames/DynamicIonpageClassnames.tsx
@@ -0,0 +1,60 @@
+import React, { useEffect, useRef, useState } from 'react';
+import {
+ IonButton,
+ IonContent,
+ IonHeader,
+ IonPage,
+ IonRouterOutlet,
+ IonTitle,
+ IonToolbar,
+} from '@ionic/react';
+import { Route } from 'react-router';
+
+interface DynamicIonpageClassnamesProps {}
+
+const DynamicIonpageClassnames: React.FC = () => {
+ return (
+
+
+
+ );
+};
+
+export default DynamicIonpageClassnames;
+
+const Page: React.FC = (props) => {
+ const [styleClass, setStyleClass] = useState('initial-class');
+ const [divClasses, setDivClasses] = useState();
+ const ref = useRef();
+ useEffect(() => {
+ if(ref.current) {
+ var observer = new MutationObserver(function (event) {
+ setDivClasses(ref.current?.className)
+ })
+
+ observer.observe(ref.current, {
+ attributes: true,
+ attributeFilter: ['class'],
+ childList: false,
+ characterData: false
+ })
+ }
+ return () => observer.disconnect()
+ }, [])
+
+
+ return (
+
+
+
+ Dynamic Ionpage Classnames
+
+
+
+ setStyleClass('other-class')}>Add Class
+
+ Div classes: {divClasses}
+
+
+ );
+};
diff --git a/packages/react/src/routing/PageManager.tsx b/packages/react/src/routing/PageManager.tsx
index 078006dd29..f78f1e2095 100644
--- a/packages/react/src/routing/PageManager.tsx
+++ b/packages/react/src/routing/PageManager.tsx
@@ -23,6 +23,9 @@ export class PageManager extends React.PureComponent {
componentDidMount() {
if (this.ionPageElementRef.current) {
+ if (this.context.isInOutlet()) {
+ this.ionPageElementRef.current.classList.add('ion-page-invisible');
+ }
this.context.registerIonPage(this.ionPageElementRef.current, this.props.routeInfo!);
this.ionPageElementRef.current.addEventListener(
'ionViewWillEnter',
@@ -87,11 +90,10 @@ export class PageManager extends React.PureComponent {
{(context) => {
this.ionLifeCycleContext = context;
- const hidePageClass = this.context.isInOutlet() ? 'ion-page-invisible' : '';
return (