Use Cases
Await a Confirm
Ask for a confirmation with useModal() and await the answer.
A useConfirm() composable wraps useModal(), so await confirm('Delete this item?') gives true or false. The answer comes once the modal has closed: Confirm, Cancel, Esc and a click outside all end in closed. open() always resolves, with 'opened' or a message, so a confirm that did not open answers false.
Preview
Preview.vue
<script setup lang="ts">
const initialResult = 'not asked yet'
const confirm = useConfirm()
const result = ref(initialResult)
async function deleteItem() {
result.value = await confirm('Delete this item?') ? 'Deleted' : 'Kept'
}
</script>
<template>
<div class="flex flex-wrap items-center justify-center gap-3">
<VButton @click="deleteItem">
Delete Item
</VButton>
<output class="inline-flex items-center gap-1.5 rounded-md border border-default px-2 py-1 text-sm text-muted">
Result: <span class="font-medium text-highlighted">{{ result }}</span>
</output>
<button type="button" class="rounded-md border border-default px-2 py-1 text-sm text-muted hover:bg-elevated/50 hover:text-highlighted disabled:pointer-events-none disabled:opacity-50" :disabled="result === initialResult" @click="result = initialResult">
Reset
</button>
</div>
</template>
useConfirm() composable
import { useModal } from 'vue-final-modal'
import ModalAwaitConfirm from '~/components/content/ModalAwaitConfirm.vue'
export function useConfirm() {
const title = ref('')
let confirmed = false
let answer: (confirmed: boolean) => void = () => {}
const { open, close } = useModal({
component: ModalAwaitConfirm,
attrs: {
title,
onConfirm() {
confirmed = true
close()
},
onCancel() {
close()
},
onClosed() {
answer(confirmed)
},
},
})
return async function confirm(message: string): Promise<boolean> {
title.value = message
confirmed = false
const answered = new Promise<boolean>(resolve => answer = resolve)
if (await open() !== 'opened')
return false
return answered
}
}
<script setup lang="ts">
import { useId } from 'vue'
import { VueFinalModal } from 'vue-final-modal'
defineProps<{
title: string
}>()
const emit = defineEmits<{
(e: 'confirm'): void
(e: 'cancel'): void
}>()
const titleId = useId()
</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"
content-transition="vfm-fade"
overlay-transition="vfm-fade"
:aria-labelledby="titleId"
>
<h1 :id="titleId" class="text-xl">
{{ title }}
</h1>
<div class="flex justify-end gap-2">
<button type="button" class="px-2 border rounded-lg" @click="emit('cancel')">
Cancel
</button>
<button type="button" class="px-2 border rounded-lg" @click="emit('confirm')">
Confirm
</button>
</div>
</VueFinalModal>
</template>