Other solutions than Nuxt Pages Plus with modal routes functionality

I started project using Nuxt 4 and I want to use modals with routing system or alternatively with params. I came across fantastic module but it's not supported anymore, I spent last two days re-creating my own custom solution but with no success . I created custom composable with Vue Router integration - provides the closest experience to nuxt-pages-plus with clean URL handling and back button support but it's far from nuxt-pages-plus. Any recommendation on how to create proven solution would be welcome.
There are also other solutions I found: Solution 1 (checked): Custom composable with Vue Router integration - provides the closest experience to nuxt-pages-plus with clean URL handling and back button support. Solution 2: Plugin-based approach - automatically detects modal routes and manages the modal stack globally. Solution 3: Layout-based system - uses Nuxt's layout system to create modal pages with background rendering. Solution 4: Modal/Dialog Manager - Component-based approach using modal/ dialog system directly.
5 Replies
kapa.ai
kapa.ai2w ago
Hi @GoldenBoy. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the available knowledge sources, there is no official or built-in Nuxt 4 feature that directly replicates the modal routing functionality of the now-unmaintained Nuxt Pages Plus module. However, there are proven patterns and tools in the Nuxt ecosystem that can help you achieve modal routing with clean URLs and back button support: 1. Custom Composable with Vue Router Integration
This is a common and effective approach. You can use Nuxt's useRoute and useRouter composables to manage modal state and URL changes. For example, you can open a modal and update the URL using navigateTo, and close the modal by navigating back or to a base route. This pattern is demonstrated in community solutions, where the modal state is synced with the route, and direct URL access to a modal is supported. The back button and browser history are handled naturally by the router. See the Stack Overflow example for a detailed implementation: when a project card is clicked, the modal opens and the URL updates; closing the modal navigates back, preserving scroll position and SPA feel. This approach is robust and aligns with Nuxt's recommended practices for routing and state management [Nuxt3 SPA modal routing example]. 2. Plugin-Based or Global Modal Manager
While the knowledge sources do not provide a ready-made plugin for modal route management, you can create a global modal manager using Nuxt plugins or composables. This would involve tracking modal state globally and integrating with the router to manage the modal stack and URLs. However, this is essentially an extension of the custom composable approach and requires careful implementation to handle edge cases. 3. Layout-Based System
Using Nuxt's layout system to render modals as part of the page layout is possible, but the knowledge sources do not provide a detailed example of this pattern for modal routing. Layouts are more commonly used for persistent UI elements rather than transient modals [Nuxt 4 layouts and pages]. 4. Component-Based Modal/Dialog Manager
Nuxt UI provides a powerful modal system via the UModal component and the useOverlay composable. You can programmatically open modals and even await their result. However, this system does not natively handle URL changes or routing integration—you would need to manually sync modal state with the router using navigateTo or similar methods [Nuxt UI Modal usage, useOverlay composable]. Summary:
The most proven and Nuxt-aligned solution is to use a custom composable that integrates with the router, as described in the Stack Overflow example. This approach gives you full control over modal state, URL synchronization, and browser history, and is compatible with Nuxt 4's routing system. There is no direct replacement for Nuxt Pages Plus, but with the tools provided by Nuxt and Nuxt UI, you can achieve a similar user experience with a bit of custom logic. If you need a concrete example or code snippet, let me know! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@616704418594816117> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
GoldenBoy
GoldenBoyOP2w ago
@kapa.ai please provide me with concrete example
kapa.ai
kapa.ai2w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Certainly! Here’s a concrete example of how to implement modal routing in Nuxt 4, based on the approach described in the Stack Overflow solution. This method uses a custom composable with Nuxt’s routing system to open modals, update the URL, and support back button navigation—all without a full page reload. 1. State Management and Routing In your main page (e.g., pages/index.vue):
<script setup lang="ts">
const route = useRoute()
const showProjectModal = useState('showProjectModal', () => false)

onMounted(() => {
if (route.params.slug) {
showProjectModal.value = route.params.slug[0]
document.getElementById('projects').scrollIntoView({ behavior: 'smooth' })
}
})
</script>

<template>
<main>
<section id="projects">
<PostCard
v-for="project in projects"
:key="project.slug"
:project="project"
@open="openProjectModal"
/>
</section>
<ProjectModal
v-if="showProjectModal"
:project="projects.find(p => p.slug === showProjectModal)"
@close="closeProjectModal"
/>
</main>
</template>
<script setup lang="ts">
const route = useRoute()
const showProjectModal = useState('showProjectModal', () => false)

onMounted(() => {
if (route.params.slug) {
showProjectModal.value = route.params.slug[0]
document.getElementById('projects').scrollIntoView({ behavior: 'smooth' })
}
})
</script>

<template>
<main>
<section id="projects">
<PostCard
v-for="project in projects"
:key="project.slug"
:project="project"
@open="openProjectModal"
/>
</section>
<ProjectModal
v-if="showProjectModal"
:project="projects.find(p => p.slug === showProjectModal)"
@close="closeProjectModal"
/>
</main>
</template>
Note: The @open and @close events are custom and will be defined in the child components. --- 2. Project Card Component components/PostCard.vue:
<script setup lang="ts">
const props = defineProps(['project'])
const showProjectModal = useState('showProjectModal', () => false)
const openProjectModal = () => {
showProjectModal.value = props.project.slug
navigateTo(`/project/${props.project.slug}`)
}
</script>

<template>
<div @click="openProjectModal">
<!-- Card content here -->
{{ project.title }}
</div>
</template>
<script setup lang="ts">
const props = defineProps(['project'])
const showProjectModal = useState('showProjectModal', () => false)
const openProjectModal = () => {
showProjectModal.value = props.project.slug
navigateTo(`/project/${props.project.slug}`)
}
</script>

<template>
<div @click="openProjectModal">
<!-- Card content here -->
{{ project.title }}
</div>
</template>
--- 3. Modal Component components/ProjectModal.vue:
<script setup lang="ts">
const props = defineProps(['project'])
const showProjectModal = useState('showProjectModal', () => false)
const closeProjectModal = () => {
showProjectModal.value = false
navigateTo(`/`)
}
</script>

<template>
<div v-if="showProjectModal" class="modal-overlay">
<div class="modal-content">
<button @click="closeProjectModal">Close</button>
<!-- Modal content for the project -->
<h2>{{ project.title }}</h2>
<p>{{ project.description }}</p>
</div>
</div>
</template>
<script setup lang="ts">
const props = defineProps(['project'])
const showProjectModal = useState('showProjectModal', () => false)
const closeProjectModal = () => {
showProjectModal.value = false
navigateTo(`/`)
}
</script>

<template>
<div v-if="showProjectModal" class="modal-overlay">
<div class="modal-content">
<button @click="closeProjectModal">Close</button>
<!-- Modal content for the project -->
<h2>{{ project.title }}</h2>
<p>{{ project.description }}</p>
</div>
</div>
</template>
--- 4. Dynamic Route (Optional) If you want to support direct linking, add a dynamic route file:
pages/project/[slug].vue
This can simply re-use your main page logic, or redirect to / and open the modal as above. --- How it Works - Clicking a project card sets the modal state and updates the URL using navigateTo. - The modal opens over the current page. - Closing the modal resets the state and navigates back to the main route. - If a user lands directly on a modal URL, the onMounted hook ensures the modal opens and scrolls to the correct section. This approach is proven and aligns with Nuxt’s best practices for SPA-like modal routing [Nuxt3 SPA modal routing example]. If you need more advanced modal management (e.g., stacking, programmatic control), you can integrate Nuxt UI’s useOverlay composable, but you’ll still need to sync modal state with the router manually [Nuxt UI Modal usage]. Let me know if you need a more advanced example or have specific requirements! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@616704418594816117> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?