N
Nuxt2d ago
Rohjans

Popup form that changes route and can be opened from anywhere in page

In my Nuxt application, I have a navbar and there I have a settings option. The idea here is that the option will change the route to /settings and this will open a popup form (UModal) and display it over the page that the user had open, it doesn't matter what the previous page was, it will show over it. I have a pages/settings/index.vue that looks like this:
<script>
definePageMeta({
modal: true
})
</script>
<script>
definePageMeta({
modal: true
})
</script>
I also changed my layouts/default.vue to have the a settings modal component there, which is where the actual form content will be hosted:
<script lang="ts" setup>
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()
const router = useRouter()

// Determine if the current route should be treated as a modal
const showSettingsModal = computed(() => route.name === 'settings')

function closeModal() {
router.back()
}
</script>

<template>
<div class="dark:bg-gray-800">
<SNavbar />

<main class="min-h-screen p-4">
<NuxtPage />
<ModalSettings v-if="showSettingsModal" @close="closeModal" />
</main>

<SFooter />
</div>
</template>
<script lang="ts" setup>
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()
const router = useRouter()

// Determine if the current route should be treated as a modal
const showSettingsModal = computed(() => route.name === 'settings')

function closeModal() {
router.back()
}
</script>

<template>
<div class="dark:bg-gray-800">
<SNavbar />

<main class="min-h-screen p-4">
<NuxtPage />
<ModalSettings v-if="showSettingsModal" @close="closeModal" />
</main>

<SFooter />
</div>
</template>
And finally, this is my ModalSettings component:
<script lang="ts" setup>
const { t: $t } = useI18n()

const emit = defineEmits(['close'])
const isOpen = ref<boolean>(true)

function handleOpenChange(state: boolean) {
if(!state) emit('close')
}
</script>

<template>
<UModal
v-model:open="isOpen"
:title="$t('Settings')"
@update:open="handleOpenChange">
<template #body>
<div class="p-4">
<!-- Your settings form goes here -->
</div>

<UButton @click="emit('close')">Close</UButton>
</template>
</UModal>
</template>
<script lang="ts" setup>
const { t: $t } = useI18n()

const emit = defineEmits(['close'])
const isOpen = ref<boolean>(true)

function handleOpenChange(state: boolean) {
if(!state) emit('close')
}
</script>

<template>
<UModal
v-model:open="isOpen"
:title="$t('Settings')"
@update:open="handleOpenChange">
<template #body>
<div class="p-4">
<!-- Your settings form goes here -->
</div>

<UButton @click="emit('close')">Close</UButton>
</template>
</UModal>
</template>
The popup opens when navigate to /settings and goes back when closed, but its background has nothing, instead of showing the previous page.
No description
14 Replies
kapa.ai
kapa.ai2d ago
Hi @Rohjans. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Your approach is very close to the recommended pattern for route-driven modals in Nuxt. The issue you’re experiencing—where the modal’s background is empty instead of showing the previous page—is due to how Nuxt handles page rendering: when you navigate to /settings, Nuxt replaces the current page with the new one, so there’s nothing "under" the modal. How to achieve the desired effect: You want the modal to appear over the previous page, regardless of what it was, and for the route to change (e.g., /settings). This is a common SPA pattern and can be achieved by: 1. Keeping the previous page rendered in the background when the modal route is active. 2. Conditionally rendering the modal based on the route, without letting Nuxt replace the page content. Solution Pattern The most robust way, as shown in the knowledge sources, is to manage modal state and routing together, using a global state or composable, and programmatically update the route without triggering a full page navigation. This is similar to the approach used for project modals in a portfolio site, where the modal opens and the URL changes, but the underlying page remains visible. The key is to not have a dedicated /settings page, but instead, treat the modal as a global overlay that is triggered by the route. #### Example Approach 1. Remove the /pages/settings/index.vue file. Instead, handle the modal entirely in your layout. 2. In your layout, watch the route and show the modal when the route matches /settings. 3. Use navigateTo to change the route when opening/closing the modal, without a full reload. Here’s how you can adapt your layout:
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()
const router = useRouter()
const showSettingsModal = computed(() => route.path === '/settings')

function closeModal() {
// Go back to the previous route
router.back()
}
</script>

<template>
<div>
<SNavbar />
<main>
<NuxtPage />
<ModalSettings v-if="showSettingsModal" @close="closeModal" />
</main>
<SFooter />
</div>
</template>
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()
const router = useRouter()
const showSettingsModal = computed(() => route.path === '/settings')

function closeModal() {
// Go back to the previous route
router.back()
}
</script>

<template>
<div>
<SNavbar />
<main>
<NuxtPage />
<ModalSettings v-if="showSettingsModal" @close="closeModal" />
</main>
<SFooter />
</div>
</template>
To open the modal from anywhere:
// In your settings button click handler
navigateTo('/settings')
// In your settings button click handler
navigateTo('/settings')
To close the modal: - Emit a close event from the modal, and in your layout, call router.back() or navigateTo(previousRoute). This pattern is confirmed to work for modals with unique URLs and no page reload, as described in the portfolio modal example from the knowledge sources. The modal overlays the current page, and the URL updates, but the underlying content does not change or reload. The trick is to not have a dedicated page for the modal, but to treat it as a global overlay controlled by the route and state, as shown in the Nuxt3 portfolio modal example and the UModal documentation. If you keep a /settings page, Nuxt will always replace the content with that page, so the background will be empty. By handling the modal in the layout and using the route as a trigger, you get the desired overlay effect. --- Summary:
- Remove the /settings page. - Show the modal in your layout when the route matches /settings. - Use navigateTo('/settings') to open, and router.back() to close. - The previous page remains visible under the modal. This approach is supported by the modal routing pattern described in the knowledge sources and is the recommended way to achieve route-driven modals in Nuxt without losing the underlying page content Nuxt3 portfolio modal example. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2d ago
<@327507766216359936> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Rohjans
RohjansOP2d ago
Here is the after picture @kapa.ai
No description
kapa.ai
kapa.ai2d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I'm sorry, but there is no information in the provided knowledge sources that describes or shows an "after picture" related to your question. If you can clarify or provide more context, I can try to help further based on the available Nuxt documentation and examples. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2d ago
<@327507766216359936> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Rohjans
RohjansOP2d ago
@kapa.ai If I remove the /settings/index.vue nuxt will show a 404 not found page, how do I stop that from happening?
kapa.ai
kapa.ai2d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- If you remove the /settings/index.vue page and navigate to /settings, Nuxt will show a 404 page because there is no route defined for /settings. To prevent this, you need to ensure that /settings is a valid route, but you don't want it to render a full page—just trigger your modal overlay. The knowledge sources do not explicitly describe a built-in way to define a route that only triggers a modal without rendering a page. However, a common approach is to create a minimal /settings.vue page that renders nothing (or a placeholder), and then use your layout to display the modal when the route matches /settings. This way, Nuxt won't show a 404, and your modal logic in the layout will handle the overlay. Alternatively, you can use route middleware to intercept navigation to /settings and handle it as needed, but the knowledge sources do not provide a direct example of this pattern for modals. In summary:
- You need to have a route for /settings to avoid a 404. - The typical workaround is to keep a minimal /settings.vue page and handle the modal display in your layout. If you need more advanced routing behavior (such as preventing the 404 without a page file), the knowledge sources do not provide enough information to confirm a fully supported solution. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2d ago
<@327507766216359936> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Rohjans
RohjansOP2d ago
@kapa.ai If I add the settings.vue file like I had done before, it will replace the page that was being redered with this placeholder, leading to the same outcome of having a blank background
kapa.ai
kapa.ai2d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- You're correct: if you add a settings.vue (or settings/index.vue) file, Nuxt will render that page when navigating to /settings, replacing the previous content and resulting in a blank or placeholder background under your modal. This is the default behavior of Nuxt's file-based routing system. The knowledge sources confirm that to achieve a modal overlay with a unique URL (like /settings) without replacing the underlying page, you should not have a dedicated page file for that route. Instead, you should handle the modal display at a higher level (such as in your layout), and use the route as a trigger for the modal, not as a page to render. This pattern is described in the solution for route-driven modals, where the modal is shown based on the route, but no new page is rendered underneath it. This avoids the blank background issue you described Nuxt3 portfolio modal example. If you do create a page file for /settings, Nuxt will always render it, replacing the previous page content. The knowledge sources do not provide a built-in way to register a route without a page file or to prevent Nuxt from rendering a 404 for a route that doesn't have a corresponding file. Therefore, the recommended approach is to handle the modal in your layout and avoid creating a page file for /settings. Summary:
- Creating a settings.vue file will always replace the current page content. - To keep the previous page as the background, do not create a page file for /settings; instead, handle the modal in your layout and use the route as a trigger. - The knowledge sources do not mention a way to register a route without a page file or to prevent a 404 in this scenario. If you need to avoid the 404, you must ensure the route exists, but this will always render its content. The overlay/modal routing pattern relies on not having a dedicated page for the modal route, as described in the knowledge sources. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2d ago
<@327507766216359936> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Rohjans
RohjansOP2d ago
@kapa.ai Is there a way I can somehow pass a parameter to NuxtPage to tell it which route to render?
kapa.ai
kapa.ai2d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Based on the knowledge sources, the <NuxtPage> component does accept a route prop, which is described as:
route: route location that has all of its components resolved. - type: RouteLocationNormalized

However, the documentation does not provide an example or further explanation of how to use the route prop to tell <NuxtPage> to render a different route than the current one. The typical usage of <NuxtPage> is to render the current route, and most examples focus on passing custom props or controlling re-rendering with pageKey rather than rendering a different route's content in place. Therefore, while the prop exists, the knowledge sources do not explicitly document or demonstrate a supported way to use <NuxtPage> to render an arbitrary route by passing a parameter. The standard pattern is for <NuxtPage> to render the current route as determined by the Nuxt router, not an arbitrary one you specify via a prop. If you need to render a different route's content, the knowledge sources do not provide enough information to confirm that this is possible or supported with <NuxtPage> at this time NuxtPage props. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2d ago
<@327507766216359936> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?