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. See style of <VueFinalModal>.

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>