Setup

How to start with Vue Final Modal, by creating a fresh new project or adding it to your Vue application.

❗️ If you came from vue-final-modal 3.x, please check the migration guide.

Play online

You can start playing with Vue Final Modal in your browser using our online sandboxes:

Play in Vue 3 on StackBlitzPlay in Nuxt 3 on StackBlitz

Installation

yarn
yarn add vue-final-modal
npm
npm install vue-final-modal
pnpm
pnpm add vue-final-modal

Plugin registration

In vue-final-modal 4, it's necessary to create a plugin by createVfm() and register it because vue-final-modal 4 has some shared context that is based on provide/inject.

Vue 3

main.ts
import { createApp } from 'vue'
import { createVfm } from 'vue-final-modal'
import App from './App.vue'

const app = createApp(App)

const vfm = createVfm()
app.use(vfm).mount('#app')

Nuxt 3

./plugins/vue-final-modal.ts
import { createVfm } from 'vue-final-modal'

export default defineNuxtPlugin((nuxtApp) => {
  const vfm = createVfm() as any

  nuxtApp.vueApp.use(vfm)
})

Import required CSS

vue-final-modal 4 has tiny size of required CSS (gzipped 0.49kb). All classes have a .vfm- prefix, so you don't have to worry about any CSS pollution.

Vue 3

main.ts
import 'vue-final-modal/style.css'

Nuxt 3

./nuxt.config.ts
export default defineNuxtConfig({
  css: ['vue-final-modal/style.css'],
})

Add <ModalsContainer> to Vue tree

<ModalsContainer> is a container for the dynamic modals that created by useModal().

You don't need to do add anything else to the <ModalsContainer>, as long as you include it in your Vue tree, you can use Dynamic modals.

You only need to put it once in your Vue app.

Vue 3

App.vue
<script setup lang="ts">
import { ModalsContainer } from 'vue-final-modal'
</script>

<template>
  <div>
    ...
    <ModalsContainer />
  </div>
</template>

Nuxt 3

layouts/default.vue
<script setup lang="ts">
import { ModalsContainer } from 'vue-final-modal'
</script>

<template>
  <div>
    Some default layout shared across all pages
    <slot />
    <ModalsContainer />
  </div>
</template>

Style a modal

Define a styled modal for yourself. Here will create a styled <ModalConfirm> with <VueFinalModal> as an example.

Plain CSS

Use plain CSS to define a <ModalConfirmPlainCss> component with <VueFinalModal>.

  • Basic example
    Preview.vue
      <script setup lang="ts">
      import { ModalsContainer, useModal } from 'vue-final-modal'
      import ModalConfirmPlainCss from './ModalConfirmPlainCss.vue'
    
      const { open, close } = useModal({
        component: ModalConfirmPlainCss,
        attrs: {
          title: 'Hello World!',
          onConfirm() {
            close()
          },
        },
        slots: {
          default: '<p>The content of the modal</p>',
        },
      })
      </script>
    
      <template>
        <VButton @click="open">
          Open Modal
        </VButton>
    
        <ModalsContainer />
      </template>
    
    ModalConfirmPlainCss.vue
      <script setup lang="ts">
      import { VueFinalModal } from 'vue-final-modal'
    
      defineProps<{
        title?: string
      }>()
    
      const emit = defineEmits<{
        (e: 'confirm'): void
      }>()
      </script>
    
      <template>
        <VueFinalModal
          class="confirm-modal"
          content-class="confirm-modal-content"
          overlay-transition="vfm-fade"
          content-transition="vfm-fade"
        >
          <h1>{{ title }}</h1>
          <slot />
          <button @click="emit('confirm')">
            Confirm
          </button>
        </VueFinalModal>
      </template>
    
      <style>
      .confirm-modal {
        display: flex;
        justify-content: center;
        align-items: center;
      }
      .confirm-modal-content {
        display: flex;
        flex-direction: column;
        padding: 1rem;
        background: #fff;
        border-radius: 0.5rem;
      }
      .confirm-modal-content > * + *{
        margin: 0.5rem 0;
      }
      .confirm-modal-content h1 {
        font-size: 1.375rem;
      }
      .confirm-modal-content button {
        margin: 0.25rem 0 0 auto;
        padding: 0 8px;
        border: 1px solid;
        border-radius: 0.5rem;
      }
      .dark .confirm-modal-content {
        background: #000;
      }
      </style>
    
Highly recommended to use TailwindCSS, WindiCSS or UnoCSS to define your modals.

Let's take TailwindCSS for example to define a <ModalConfirm> component with <VueFinalModal>.

  • Basic example
    Preview.vue
      <script setup lang="ts">
      import { ModalsContainer, useModal } from 'vue-final-modal'
      import ModalConfirm from './ModalConfirm.vue'
      const { open, close } = useModal({
        component: ModalConfirm,
        attrs: {
          title: 'Hello World!',
          onConfirm() {
            close()
          },
        },
        slots: {
          default: '<p>UseModal: The content of the modal</p>',
        },
      })
      </script>
    
      <template>
        <VButton @click="() => open()">
          Open Modal
        </VButton>
    
        <ModalsContainer />
      </template>
    
    ModalConfirm.vue
      <script setup lang="ts">
      import { VueFinalModal } from 'vue-final-modal'
    
      defineProps<{
        title?: string
      }>()
    
      const emit = defineEmits<{
        (e: 'confirm'): void
      }>()
      </script>
    
      <template>
        <VueFinalModal
          class="flex justify-center items-center"
          content-class="flex flex-col max-w-xl mx-4 p-4 bg-white dark:bg-gray-900 border dark:border-gray-700 rounded-lg space-y-2"
        >
          <h1 class="text-xl">
            {{ title }}
          </h1>
          <slot />
          <button class="mt-1 ml-auto px-2 border rounded-lg" @click="emit('confirm')">
            Confirm
          </button>
        </VueFinalModal>
      </template>
    

Control a modal

There are three ways to control a modal component.

Take the <ModalConfirm> component we built on previous section as an example:

useModal()

useModal() is a composable function that is used to create a dynamic modal, then you can control the modal programmatically.

As a requirement to using useModal() you must add <ModalsContainer> to your main App.vue file.

  • Basic example
    Preview.vue
      <script setup lang="ts">
      import { ModalsContainer, useModal } from 'vue-final-modal'
      import ModalConfirm from './ModalConfirm.vue'
    
      const { open, close } = useModal({
        component: ModalConfirm,
        attrs: {
          title: 'Hello World!',
          onConfirm() {
            close()
          },
        },
        slots: {
          default: '<p>UseModal: The content of the modal</p>',
        },
      })
      </script>
    
      <template>
        <VButton @click="() => open()">
          Open Modal
        </VButton>
    
        <ModalsContainer />
      </template>
    

v-model

Use v-model for show/hide a modal.

  • Basic example
    Preview.vue
      <script setup lang="ts">
      const show = ref(false)
    
      function confirm() {
        show.value = false
      }
      </script>
    
      <template>
        <VButton @click="show = true">
          Open Modal
        </VButton>
    
        <ModalConfirm
          v-model="show"
          title="Hello World!"
          @confirm="() => confirm()"
        >
          <p>VModel: The content of the modal</p>
        </ModalConfirm>
      </template>
    

modalId

modelValue is not a required prop for <VueFinalModal>. Without using v-model, you can also use useVfm() composable function to control the modal by given a modalId.

  • Basic example
    Preview.vue
      <script setup lang="ts">
      import { useVfm } from 'vue-final-modal'
    
      const vfm = useVfm()
      const modalId = Symbol('modalId')
    
      function confirm() {
        vfm.close(modalId)
      }
      </script>
    
      <template>
        <VButton @click="() => vfm.open(modalId)">
          Open Modal
        </VButton>
    
        <ModalConfirm
          :modal-id="modalId"
          title="Hello World!"
          @confirm="() => confirm()"
        >
          <p>The content of the modal</p>
        </ModalConfirm>
      </template>