Ionic 6 introduced a new way to create modals, the ion-modal element.

According to the docs, ion-modal can be used by writing the component directly in your template. This reduces the number of handlers you need to wire up in order to present the modal.

One great use case I found for this is when you’re sharing a service instance.

For example, let’s say you have a parent component, and that component has a service provider declared as a component provider.

If you use the old way to trigger modals, you´d have to declare the service in the modal provider or in root to be able to use it in the modal, but if you declare it in the modal provier, it would be a different instance that in the parent component.

By the way, do you want to jump-start your development using the Firebase modular SDK with AngularFire?

Download my free book that will take you from creating an app to properly using Firebase Auth and Firestore.

Download the book now

To use them, you would use the <ion-modal> element directly in your template instead of using the ModalController inside of your class to call a separate component.

<ion-content class="ion-padding">
  <ion-button id="open-modal" expand="block">Open</ion-button>

  <ion-modal trigger="open-modal">
    <ng-template> </ng-template>
  </ion-modal>
</ion-content>

As you see, we use the <ion-modal> element with the trigger="open-modal" attribute, and we have a button with the same ID, this button will open our modal.

And inside of the <ng-template> you can add another component, or directly add your elements there so that they can be rendered on the modal.

Ionic page with a button

For example:

<ion-modal #modal trigger="open-modal">
  <ng-template>
    <ion-header>
      <ion-toolbar>
        <ion-title>Confirm Your Details</ion-title>
      </ion-toolbar>
    </ion-header>
    <ion-content class="ion-padding">
      <p>
        Click <strong>confirm</strong> to set your name (Jorge) and age (36) or <strong>cancel</strong> to dismiss this
        modal.
      </p>
      <ion-button class="ion-margin" shape="round" expand="full" fill="outline" (click)="dismiss()">Cancel</ion-button>
      <ion-button class="ion-margin" shape="round" expand="full" (click)="confirm()">Confirm</ion-button>
    </ion-content>
  </ng-template>
</ion-modal>

Here we have a simple template that is showing some text, a cancel and confirm button, the idea is that those buttons cal some functions on the template.

Ionic inline modal

The cancel button will call the dismiss function, that dismisses the modal, and the confirm button will dismiss the modal, but passing some information back to the parent component/page.

import { Component, ViewChild } from '@angular/core';
import { IonModal } from '@ionic/angular';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
  @ViewChild(IonModal) modal: IonModal;
  message = `Click Open to show the modal.`;

  dismiss() {
    this.modal.dismiss(null, 'dismiss');
  }

  confirm() {
    const person: Person = {
      name: 'Jorge Vergara',
      age: 36,
    };
    this.modal.dismiss(person, 'confirm');
  }
}

interface Person {
  name: string;
  age: number;
}

We’re using IonModal from import { IonModal } from '@ionic/angular'; and calling the dismiss() function, this function takes 2 parameters, an object that you can use as data passed back to the parent component, and a role.

Now to access that data, we’re going to create a new function called onWillDismiss() and assign it to the willDismiss method of the modal:

<ion-modal trigger="open-modal" (willDismiss)="onWillDismiss($event)"></ion-modal>
onWillDismiss(modalEvent: Event) {
  const customModalEvent = modalEvent as ModalCustomEvent;
  if (customModalEvent.detail.role === 'dismiss') {
    this.message = `User dismissed the modal, so nothing do to here.`;
  }
  if (customModalEvent.detail.role === 'confirm') {
    const { name, age } = customModalEvent.detail.data;
    this.message = `User confirmed their details, their name is ${name}, and they are ${age} years old.`;
  }
}

We’re getting the event, and from that event we’re accessing the detail property, there we have both the data and the role.

If the role is dismiss we don’t do anything, because we see the user canceled the modal, of the rol is confirm we do whatever logic we were going to do, in out case it’s showing a different message.

Ionic inline modal

Ionic inline modal

And we created a ModalCustomEvent interface to properly type the returning data:

interface ModalCustomEvent extends CustomEvent {
  target: HTMLIonModalElement;
  detail: {
    data: Person,
    role: string,
  };
}

Another thing we can do is to change the way our modal looks, and transform it into a card modal by changing the presentingElement.

Ionic inline modal

<ion-modal [presentingElement]="presentingElement"></ion-modal>
import { IonRouterOutlet } from '@ionic/angular';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
  presentingElement = this.ionRouterOutlet.nativeEl;
  constructor(private readonly ionRouterOutlet: IonRouterOutlet) {}
}

And that’s it, have you created inline modals yet? Do you find them easier to create than regular controller modals?

You can find the full source code for this example in Github