It is easy to preserve scroll forms in Inertia, however within Modals, I found it a bit tricky, is there a trick to do it?
<script setup>
import Modal from '@/Components/Modal.vue'
import { useForm, Head } from '@inertiajs/vue3'
const form = useForm({
name: '',
email: '',
subject: '',
message: '',
})
const submit = () => {
form.post(route('contact.send'), {
preserveScroll: true,
onSuccess: () => form.reset(),
});
};
</script>
I have this, but it doesn't work.
Hmm, I can’t think of why this wouldn’t work out the box.
Could you post your modal wrapper so I can experiment with this locally?
Yeah of course,
<script setup>
import Modal from '@/Components/Modal.vue'
import { useForm, Head } from '@inertiajs/vue3'
import { useModal } from 'momentum-modal'
const { close } = useModal()
const form = useForm({
name: '',
email: '',
subject: '',
message: '',
})
const submit = () => {
form.post(route('contact.send'), {
preserveScroll: true,
onSuccess: () => close(),
});
};
</script>
<template>
<Modal>
<div class="text-center">
<h3 class="block text-2xl font-bold text-gray-800">Contact Us</h3>
</div>
<div class="mt-5">
<form v-on:submit.prevent="submit">
<div class="grid gap-y-4">
<div>
<label for="name" class="block text-sm mb-2">Name</label>
<div class="relative">
<input type="text" id="name" name="name" v-model="form.name"
class="py-3 px-4 block w-full border-gray-200 rounded-lg text-sm focus:border-red-500 focus:ring-red-500 disabled:opacity-50 disabled:pointer-events-none"
aria-describedby="name-error">
<div v-if="form.errors.name" class="absolute inset-y-0 end-0 pointer-events-none pe-3 mt-3">
<svg class="size-5 text-red-500" width="16" height="16" fill="currentColor"
viewBox="0 0 16 16">
<path
d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z" />
</svg>
</div>
</div>
<p v-if="form.errors.name" class="text-xs text-red-600 mt-2" id="name-error">{{
form.errors.name }}</p>
</div>
<div>
<label for="email" class="block text-sm mb-2">Email address</label>
<div class="relative">
<input type="text" id="email" name="email" v-model="form.email"
class="py-3 px-4 block w-full border-gray-200 rounded-lg text-sm focus:border-red-500 focus:ring-red-500 disabled:opacity-50 disabled:pointer-events-none"
aria-describedby="email-error">
<div v-if="form.errors.email"
class="absolute inset-y-0 end-0 pointer-events-none pe-3 mt-3">
<svg class="size-5 text-red-500" width="16" height="16" fill="currentColor"
viewBox="0 0 16 16">
<path
d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z" />
</svg>
</div>
</div>
<p v-if="form.errors.email" class="text-xs text-red-600 mt-2" id="email-error">{{
form.errors.email }}</p>
</div>
<div>
<label for="subject" class="block text-sm mb-2">Subject</label>
<div class="relative">
<input type="text" id="subject" name="subject" v-model="form.subject"
class="py-3 px-4 block w-full border-gray-200 rounded-lg text-sm focus:border-red-500 focus:ring-red-500 disabled:opacity-50 disabled:pointer-events-none"
aria-describedby="subject-error">
<div v-if="form.errors.subject"
class="absolute inset-y-0 end-0 pointer-events-none pe-3 mt-3">
<svg class="size-5 text-red-500" width="16" height="16" fill="currentColor"
viewBox="0 0 16 16">
<path
d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z" />
</svg>
</div>
</div>
<p v-if="form.errors.subject" class="text-xs text-red-600 mt-2" id="subject-error">{{
form.errors.subject }}</p>
</div>
<div>
<label for="message" class="block text-sm mb-2">Message</label>
<div class="relative">
<textarea id="message" name="message" v-model="form.message"
class="py-3 px-4 block w-full border-gray-200 rounded-lg text-sm focus:border-red-500 focus:ring-red-500 disabled:opacity-50 disabled:pointer-events-none rows-4"
aria-describedby="message-error"></textarea>
<div v-if="form.errors.message"
class="absolute inset-y-0 end-0 pointer-events-none pe-3 mt-3">
<svg class="size-5 text-red-500" width="16" height="16" fill="currentColor"
viewBox="0 0 16 16">
<path
d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z" />
</svg>
</div>
</div>
<p v-if="form.errors.message" class="text-xs text-red-600 mt-2" id="message-error">{{
form.errors.message }}</p>
</div>
<button type="submit" :disabled="form.processing"
class="w-full py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-red-600 text-white hover:bg-red-700 focus:outline-none focus:bg-red-700 disabled:opacity-50 disabled:pointer-events-none">Send
Message</button>
</div>
</form>
</div>
</Modal>
<Head title="Contact" />
</template>
Edit: I forgot to include the modal Componet
<script setup>
import { TransitionRoot, TransitionChild, Dialog, DialogPanel } from '@headlessui/vue'
import { useModal } from 'momentum-modal'
const { show, close, redirect } = useModal()
</script>
<template>
<TransitionRoot :show="show">
<Dialog as="div" class="relative z-50" v-on:close="close">
<TransitionChild as="template" v-on:after-leave="redirect" enter="duration-500 ease-out"
enter-from="opacity-0" enter-to="opacity-100" leave="duration-500 ease-out" leave-from="opacity-100"
leave-to="opacity-0">
<div class="bg-slate-800/75 fixed inset-0"></div>
</TransitionChild>
<div class="hs-overlay size-full fixed top-0 start-0 z-[80] overflow-x-hidden overflow-y-auto">
<div class="mt-7 transition-all sm:max-w-lg sm:w-full m-3 sm:mx-auto">
<TransitionChild as="template" enter="duration-500 ease-out" enter-from="opacity-0 scale-90"
enter-to="opacity-100 scale-100" leave="duration-500 ease-out"
leave-from="opacity-100 scale-100" leave-to="opacity-0 scale-90">
<DialogPanel v-bind="$attrs"
class="bg-white border border-gray-200 rounded-xl shadow-sm">
<div class="p-4 sm:p-7">
<slot />
</div>
</DialogPanel>
</TransitionChild>
</div>
</div>
</Dialog>
</TransitionRoot>
</template>
Sorry for the delay on this. I'm having trouble re-creating locally.
What's happening within your modal when you submit the form? Is the background page scrolling to the top, or is it jumping up within your modal (if you have a scrollable modal).
I have solved the issue by looking more into the documents of inertia, just had to add preserve scroll to the Link as well, excuse the complication!