What about ion-page (or IonPage)?

I was looking at the sample code for ion-menu (here) and found the following code sample, which looks strange to me:

...
<div class="ion-page" id="main-content">
  <ion-header>
    <ion-toolbar>
    ...

Basically all the elements here have ion-abc tags. But for ion-page it’s a div with a class attribute.
In my code IonPage can be imported and used without problems (react codebase).

I couldn’t find it in the docs.
But there is a similarly named IonicPage in the old v3 docs. Is this somehow related?

So, what is ion-page and how is it used correctly?

So ionPage is more of an internal API that we use as a structure component.
In Angular, we automatically apply this to the component that is connected to a route, so we don’t force people to add it to the dom.

But react doesn’t behave the same, so we needed a component that creates a div with a class of ion-page.
We don’t really document as it’s mostly just used internally for navigation.

If you’re in a React project, just make sure your components connected to a route use IonPage as the wrapper.

function HomePage{
  return (
   <IonPage>...</IonPage>
  )
}

But Angular folks do not need to worry about this.

5 Likes

Oh, I wasn’t aware of that at all.
What happens if you don’t wrap your routes in an IonPage?

The docs entry on react navigation never explicitly mentions IonPage. They do talk about “pages” but it sounds more like a general design concept than an actual tag that you have to use.

At the bottom of the docs entry there is also a link to a community tutorial on react and routing. If it is necessary to wrap your routes in pages, then that tutorial is broken. It uses an IonPage toplevel, directly below IonApp. But not in connection with routing.

I experimented with this and it turns out, if routes are not wrapped in IonPages, they don’t work at all.

Here is a simple example. It sets up three routes, two of them with an IonPage, the third without. If the route has an IonPage, there is a minimal transition animation. Without an IonPage, the content is not displayed properly ! In this example, the about page does not render:


const About: React.FC = () => {
  return (
    <div>
      <IonContent>
        <IonLabel> about</IonLabel>
        <IonButton routerLink='/home'>back to home</IonButton>
      </IonContent>
    </div>
  );
};
const Config: React.FC = () => {
  return (
    <IonPage>
      <IonContent>
        <IonLabel> config</IonLabel>
        <IonButton routerLink='/home'>back to home</IonButton>
      </IonContent>
    </IonPage>
  );
};
const Home: React.FC = () => {
  return (
    <IonPage>
      <IonContent>
        <IonLabel> home</IonLabel>
        <IonButton routerLink='/about'>about</IonButton>
        <IonButton routerLink='/config'>config</IonButton>
      </IonContent>
    </IonPage>
  );
};

And in App.tsx a router is set up:

const App: React.FC = () => (
  <IonApp>
    <IonReactRouter>
      <IonRouterOutlet>
        <Route path="/home" component={Home} exact={true} />
        <Route path="/about" component={About} exact={true} />
        <Route path="/config" component={Config} exact={true} />
        <Route exact path="/" render={() => <Redirect to="/home" />} />
      </IonRouterOutlet>
    </IonReactRouter>
  </IonApp>
);

yep, like I said, ionPage is more for the routers to know “what am I animating in?”

1 Like

Hi, sorry to indrude this question, but I want to verify that this is good practive for ionic.

When using ng-content to fill ion-content, another wrapper (in this example ‘my-custom-header’) is placed between ion-content and ion-page, resulting in wrong scrollheights.

This can be fixed by adding the class “ion-page” to any wrapper that is used before ion-content.

<ion-app>
     <ion-router-outlet>
         <example-page class="ion-page">
                <my-custom-header  class="ion-page">
                   <!-- header + content are part of the custom header-->
                  <ion-header>
                      ...
                  </ion-header>
                  <ion-content class="ion-padding">
                     <!-- here comes anything inserted from the actual parent "example-page", replacing the ng-content -->
                      ...
                  </ion-content>
            </my-custom-header>
       <example-page>
    </ion-router-outlet>
</ion-app>

Is this a correct workaround or should it be done otherwise?

1 Like

Mmm, can’t tell if it’s the same code or how you actually have it done…, but you should not be adding ion-page to elements.

Again, ion-page and .ion-page (component and css class) internally have special meanings. throwing them on various elements is not something you should be done.

If the class ion-page should not be used,
is there an official way to make ng-content work with ionic?

Here is a full example of it:

App-Shell-Basic
Provides same (modified) ionheader + ioncontent for every page:

<ion-header> 
  <ion-toolbar>
    <ion-buttons slot="start">
      <ion-button (click)="backButtonAction()">
        <ion-icon slot="icon-only" name="arrow-back" color="light"></ion-icon>
      </ion-button>
    </ion-buttons>   
  </ion-toolbar>
</ion-header>

<ion-content>

  <ion-refresher *ngIf="isPlatformBrowser" slot="fixed" (ionRefresh)="doRefresh($event)">
    <ion-refresher-content></ion-refresher-content>
  </ion-refresher>

  <!-- here is the actual page content, different for each page -->
  <ng-content></ng-content>  

</ion-content>

<!-- here comes all ion-fabs and ion-footers, different for each page-->
<ng-content select="ion-fab"></ng-content>
<ng-content select="ion-footer"></ng-content>

Example-page
Is one of the pages which uses this header+content

 <app-shell-basic class="ion-page"> 
	   <!-- page content-->
	  <div>
		  I am the content of the page
	  </div>
	  
	 
	   <!-- page fab buttons-->
	  <ion-fab vertical="bottom" horizontal="end" slot="fixed">
		<ion-fab-button (click)="doFabAction()>
		   Click me
		</ion-fab-button>
	  </ion-fab>
	  
	   <!-- page footer->	   
	  <ion-footer>
		<ion-toolbar>
		  <ion-button (click)="doFooterAction()">
			My Footer Button
		  </ion-button>
		</ion-toolbar>
	  </ion-footer>	  
</app-shell-basic>

This results in following final page:

 <ion-app>
     <ion-router-outlet>
         <example-page class="ion-page"> 
			<!-- Here we must add the additional element 'app-shell-basic' between ion-app + ion-content leads to ionic wronly sizing the ion-content. Adding class 'ion-page' manually fixes this problem.-->
			<app-shell-basic class="ion-page">
				<ion-header> 
				  <ion-toolbar>
					<ion-buttons slot="start">
					  <ion-button (click)="backButtonAction()">
						<ion-icon slot="icon-only" name="arrow-back" color="light"></ion-icon>
					  </ion-button>
					</ion-buttons>   
				  </ion-toolbar>
				</ion-header>

				<ion-content>

					<ion-refresher *ngIf="isPlatformBrowser" slot="fixed" (ionRefresh)="doRefresh($event)">
						<ion-refresher-content></ion-refresher-content>
					</ion-refresher>

					<!-- here is the actual page content, different for each page -->  
					<!-- page content-->
					<div>
						I am the content of the page
					</div>
					  

				</ion-content>

				<!-- here comes all ion-fabs and ion-footers, different for each page-->
				<!-- page fab buttons-->
				<ion-fab vertical="bottom" horizontal="end" slot="fixed">
					<ion-fab-button (click)="doFabAction()>
					   Click me
					</ion-fab-button>
				</ion-fab>
				  
				<!-- page footer->	   
				<ion-footer>
					<ion-toolbar>
					  <ion-button (click)="doFooterAction()">
						My Footer Button
					  </ion-button>
					</ion-toolbar>
				</ion-footer>
			</app-shell-basic>
		</example-page>
    </ion-router-outlet>
</ion-app>

If ‘ion-page’ should not be used, does this mean this is a bug I should open for ionic? (usage of ng-content kills automatic ionic resizing)

I also realized that only the parent component connected to the route needs to be wrapped in <IonPage>. If the child components are wrapped in <IonPage> too, they will not render.

1 Like

@KevinB1, I also have this problem.

All of ui-inspection’s content isn’t shown in the following example:

But if I move class=“ion-page” from im-inspection to ui-inspection it looks fine:

@mhartington, if we shouldn’t fiddle with ion-page, how can we get the content to show if we use ion-content in an Angular component (ui-inspection) that’s wrapped by the Angular component (im-inspection) routed to.

You dont, to be honest. The patter you’re describing of having a “common” UI that acts as a shell does account for the layout that Ionic expects. Since .ion-page expect ion-header, ion-content, or ion-footer as direct children, wrapping things inside another component breaks this.