DEV Community

Cover image for Using stacked modals with Ionic Vue
Giulio Ganci
Giulio Ganci

Posted on

Using stacked modals with Ionic Vue

Since ionic 5 has been released it is possible to use a new component of the iOS UI Kit that allows you to open content in a temporary mode that’s separate from the user's previous current context.

These contents are presented in a stack managed by the ionic modal controller and while they work very well on @ionic/angular and @ionic/react they are not yet fully supported in @ionic/vue but there is a way to have this feature working using a workaround, so be careful if using it in production.

In order to use stacked modals you need to have access to the current IonRouterOutlet reference but currently there is no official method to have a reference to it, so we use the vue3 provide method to serve a reference from the app component and the inject method to access it in each child component.

/src/App.vue

<template>
  <IonApp>
    <ion-router-outlet
      ref="routerOuteletRef"
      id="main-content"
    ></ion-router-outlet>
  </IonApp>
</template>

<script lang="ts">
import { IonApp, IonRouterOutlet } from "@ionic/vue";
import { defineComponent, ref, provide } from "vue";

export default defineComponent({
  name: "App",
  components: {
    IonApp,
    IonRouterOutlet,
  },
  setup() {
    // create an empty ref
    const routerOuteletRef = ref(null);
    // provide the value in the component hierarchy
    provide("routerOutlet", routerOuteletRef);

    return { routerOuteletRef };
  },
});
</script>

Enter fullscreen mode Exit fullscreen mode

Now we use a generic "Home" component which contains a button that opens a new modal view of the same "Home" component

Note that stacked modals are activated by passing the presentingElement option to the modal controller.

/src/view/Home.vue

<script lang="ts">
import { defineComponent, inject } from "vue";
import { modalController } from "@ionic/vue"

import Home from "./Home.vue";

export default defineComponent({
  name: "Home",
  setup() {
    const outlet: any = inject("routerOutlet");

    const openModal = async () => {
      // use the last presenting element
      const top = (await modalController.getTop()) || outlet.value.$el;

      const modal = await modalController.create({
        component: Home,
        swipeToClose: true,
        presentingElement: top,
      });
      return modal.present();
    };

    return {
      openModal,
    };
  },
});
</script>
Enter fullscreen mode Exit fullscreen mode

Here a fully working example in code sandbox.

Top comments (0)