Vue Final Modal
Use Cases

Modal Keep Alive

Keep a dynamic modal mounted after it is closed, so its state survives the next open().

By default a modal created with useModal() is unmounted when it closes, so the next open() starts from a fresh component. With keepAlive: true the modal stays mounted (hidden with display: none) and keeps its state: form drafts, scroll position, anything the component holds.

Type a draft in both modals below, close them and open them again. The kept-alive modal still has the draft, the default one does not. destroy() unmounts a kept-alive modal and throws its state away; the next open() mounts it again.

Preview

Preview.vue
  <script setup lang="ts">
  import { onBeforeUnmount } from 'vue'
  import { useModal } from 'vue-final-modal'
  import ModalKeepAlive from './ModalKeepAlive.vue'

  const keptAlive = useModal({
    keepAlive: true,
    component: ModalKeepAlive,
    attrs: {
      title: 'keepAlive: true',
      onClose() {
        keptAlive.close()
      },
    },
  })

  const unmountedOnClose = useModal({
    component: ModalKeepAlive,
    attrs: {
      title: 'keepAlive: false (default)',
      onClose() {
        unmountedOnClose.close()
      },
    },
  })

  onBeforeUnmount(() => keptAlive.destroy())
  </script>

  <template>
    <VButton @click="() => keptAlive.open()">
      Open kept-alive modal
    </VButton>
    <VButton @click="() => unmountedOnClose.open()">
      Open default modal
    </VButton>
    <VButton @click="() => keptAlive.destroy()">
      Destroy kept-alive modal
    </VButton>
  </template>

When to use it

  • The modal holds state that should survive a close, such as a half-filled form or a scrolled list.
  • The modal is heavy to mount and is opened often.

A kept-alive modal is not destroyed when the component that created it unmounts, so call destroy() yourself when it is no longer needed.

<ModalKeepAlive> component

  <script setup lang="ts">
  import { ref } from 'vue'
  import { VueFinalModal } from 'vue-final-modal'

  defineProps<{
    title?: string
  }>()

  const emit = defineEmits<{
    (e: 'close'): void
  }>()

  const draft = ref('')
  </script>

  <template>
    <VueFinalModal
      class="flex justify-center items-center"
      content-class="flex flex-col w-full max-w-md mx-4 p-4 bg-white dark:bg-gray-900 border dark:border-gray-700 rounded-lg space-y-2"
      content-transition="vfm-fade"
      overlay-transition="vfm-fade"
    >
      <h1 class="text-xl">
        {{ title }}
      </h1>
      <textarea
        v-model="draft"
        class="w-full h-24 p-2 border dark:border-gray-700 rounded-lg bg-transparent"
        placeholder="Type a draft, close the modal, then open it again"
      />
      <button class="mt-1 ml-auto px-2 border rounded-lg" @click="emit('close')">
        Close
      </button>
    </VueFinalModal>
  </template>
Copyright © 2026