Modal Routes

Modal Routes can navigate modal routes with real-time URL changes for seamless browsing.

For example, imagine your website has a page called /shop that lists various product links. When a user clicks on a product link, such as /item/5, the details of the product are displayed in a modal, while the URL is simultaneously updated to /item/5.

Modal Routes

This approach offers several advantages. Not only does it help users intuitively understand their current location on the site, but it also allows them to copy and share the URL with others easily.

Modal Routes

When a user navigates directly to /item/5, the page is displayed normally instead of as a modal. This setup ensures that the user experience is seamless, whether accessing the item details through a link on the shop page or by entering the URL directly into the browser.

Usage

Before we start, make sure you have installed nuxt-pages-plus module in your Nuxt project.

For instance, here's how your original Nuxt project setup with two routes: / and /info would look like:

pages/index.vue
<template>
  <div>
    <NuxtLink to="/info">Go Info</NuxtLink>
  </div>
</template>
pages/info.vue
<template>
  <div>
    <NuxtLink to="/">Go Home</NuxtLink>
  </div>
</template>
app.vue
<template>
  <NuxtPage />
</template>

In this tutorial, we will add a modal route for /info and add a button on index.vue. When you click the button, an info modal will pop up on the page, and the URL will change to /info.

Preparation

First, you need to change your <NuxtPage /> in your app.vue file.

Option 1: Replace <NuxtPage /> with <PlusModalNuxtPage />.

app.vue
<template>
-  <NuxtPage />
+  <PlusModalNuxtPage />
</template>

Option 2: You can use PlusModalNuxtPage to wrap your NuxtPage component and pass the route prop to it.

app.vue
<template>
  <PlusModalNuxtPage v-slot="{ route }">
    <NuxtPage :route="route" />
  </PlusModalNuxtPage>
</template>

Adding Modal Routes

First, add a new file @my-modal/info.vue (or any name you prefer) to your ~/pages directory:

pages/@my-modal/info.vue
<template>
  <Teleport to="body">
    <div>
      <p>I am info modal</p>
      <button @click="$modalRouter.close()">Close</button>
    </div>
  </Teleport>
</template>
  • <Teleport> is a native component in Vue 3 that allows you to move components to a specified location, here moving the modal to the body of the document.
  • $modalRouter.close() is a method used to close the modal.

Displaying Modal Routes

After creating the modal route, you can now display the modal route on your page by adding a <PlusModalLink> and <PlusModalPage> component.

pages/index.vue
<template>
  <div>
    <NuxtLink to="/info">Go Info</NuxtLink>
+    <PlusModalLink to="/info">Show Info Modal</PlusModalLink>
+    <PlusModalPage name="my-modal" />
  </div>
</template>
  • PlusModalLink functions similarly to NuxtLink but performs soft-navigation that changes the URL to /info without a full page navigation.
  • PlusModalPage in here is used to display the content of the my-modal modal route. When the URL is /info, it will display the content from @my-modal/info.vue. You can add <PlusModalPage> to layout for showing modal in all pages or add it to a specific page like this example.

That's it! You've successfully added a modal route to your Nuxt application.

How it works?

Modal Routes uses the History API for saving the "background view" of the modal and pass it's route to the route prop of RouterView. There is a Vue RFC by @posva demonstrating the idea.

When a modal route is opened, you can navigate to another modal route while keeping the modal open.

Consider the example of developing a gallery application:

pages/home.vue
<template>
  <div>
    <PlusModalLink to="/image/1">
      <img src="/image/1" />
    </PlusModalLink>

    <PlusModalPage name="modal" />
  </div>
</template>

When a user clicks on an image link (/image/1) from the /home page, a modal opens displaying detailed information about the image. Inside the modal, there are "Next" and "Previous" buttons allowing the user to browse through images:

pages/@modal/image/[id].vue
<template>
  <div>
    Image Modal
    <PlusModalLink :to="`/image/${parseInt(id) - 1}`">Prev</PlusModalLink>
    <img :src="`/image/${id}`" />
    <PlusModalLink :to="`/image/${parseInt(id) + 1}`">Next</PlusModalLink>

    <button @click="$modalRouter.close()">Close</button>
  </div>
</template>

The modal remains open as the user navigates through images, and when the "Close" button is pressed, the modal closes and the route returns to /home.

Nested Navigation in Modal

Continuing with the gallery application example, suppose you want to open another set of modals within @modal/image/[id].vue to view comments, such as /comments/[id].

pages/@modal/image/[id].vue
<template>
  <div>
    Image Modal
    <PlusModalLink :to="`/image/${parseInt(id) - 1}`">Prev</PlusModalLink>
    <img :src="`/image/${id}`" />
    <PlusModalLink :to="`/image/${parseInt(id) + 1}`">Next</PlusModalLink>

    <PlusModalLink :to="`/comments/${id}`">Comments</PlusModalLink>

    <button @click="$modalRouter.close()">Close</button>
  </div>
</template>

pages/@modal/comments/[id].vue
<template>
  <div>
    Comments
    <CommentsComponent :id="id" />
    <button @click="$modalRouter.close()">Close</button>
  </div>
</template>

The challenge arises when pressing the "Close" button in the comments modal, the default behavior would take you back to /home. To ensure that closing the comments modal takes you back to the image modal instead of /home, you can utilize the open prop on PlusModalLink.

pages/@modal/image/[id].vue
<template>
  <div>
    Image Modal
    <PlusModalLink :to="`/image/${parseInt(id) - 1}`">Prev</PlusModalLink>
    <img :src="`/image/${id}`" />
    <PlusModalLink :to="`/image/${parseInt(id) + 1}`">Next</PlusModalLink>

    <PlusModalLink open :to="`/comments/${id}`">Comments</PlusModalLink>

    <button @click="$modalRouter.close()">Close</button>
  </div>
</template>

This adjustment ensures that upon closing the comments modal, the navigation returns to the image modal instead of defaulting back to /home. This enhances the continuity and user experience of navigating through modals within your application.

Examples