Vuetify, a popular Material Design framework for Vue, provides a wide range of UI components, including highly customizable dialogs. This article will guide you through building composable programmatic dialogs using Vue and Vuetify, allowing you to manage dialogs efficiently and flexibly.Creating programmatic dialogs in Vue using Vuetify allows developers to dynamically generate dialogs that enhance the user experience without cluttering the template with numerous dialog components.
## with npm
npm create vuetify@latest
## with yarn
yarn create vuetify
## with pnpm
pnpm create vuetify
## with bun
bun create vuetify
Create a new dialog component in src/components
, here I will create a file names Dialog.vue
touch src/dialogs/Dialog.vue
The content of this file is :
<template>
<v-dialog v-model="open" width="50%" persistent max-width="60%">
<v-card :title="title">
<v-card-text>{{ message }}</v-card-text>
<v-card-actions>
<v-btn color="success" @click="submitDialog">{{ submitText }}</v-btn>
<v-btn color="error" @click="cancelDialog">{{ cancelText }}</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script setup>
const open = defineModel({ default: false, type: Boolean })
const emits = defineEmits(["submit", "cancel"])
const props = defineProps({
title: {
type: String,
default: () => ("Attention"),
},
message: {
type: String,
default: () => (null),
},
submitText: {
type: String,
default: () => ("Submit"),
},
cancelText: {
type: String,
default: () => ("Cancel"),
}
}
)
const submitDialog = () => {
emits('submit')
open.value=false
}
const cancelDialog = () => {
emits('cancel')
open.value=false
}
</script>
<v-dialog>
: A Vuetify component that creates a modal dialog box.persistent
: Prevents the user from closing the dialog by clicking outside of it.:title="title"
: Binds the title
prop to the card title.<v-btn color="success">
: A button with a green color labeled with the submitText
prop (default is "Submit").<v-btn color="error">
: A button with a red color labeled with the cancelText
prop (default is "Cancel").And in the script section
const open = defineModel({ default: false, type: Boolean })
: This line creates a reactive open
property with a default value of false
and specifies that it should be of type Boolean
. This property controls whether the dialog is visible.const emits = defineEmits(["submit", "cancel"])
: Defines events that the component can emit, namely "submit" and "cancel". These events would typically be triggered when the corresponding buttons are clicked, but they are not explicitly emitted in the current code.const props = defineProps({ ... })
: Defines the properties (props
) that the component accepts:
title
: A String
prop with a default value of "Attention".message
: A String
prop that defaults to null
.submitText
: A String
prop with a default value of "Submit".cancelText
: A String
prop with a default value of "Cancel".mkdir -p src/composables && touch /src/composable/useDialog.js
In the useDialog.js
file copy and past this coce :
import { createApp, mergeProps } from 'vue'
import Dialog from '@/components/Dialog.vue'
import vuetify from '@/plugins/vuetify'
export const getVAppRoot = () => document.body
export const createContainer = () => document.createElement('div')
export const useDialog = (props) => {
const rootElement = getVAppRoot()
const container = createContainer()
return new Promise((resolve) => {
const componentApp = createApp(Dialog, mergeProps(
props,
{ modelValue: true },
{
onSubmit() {
resolve(true)
},
onCancel() {
resolve(false)
}
}
))
rootElement.appendChild(container)
componentApp.use(vuetify).mount(container)
})
}
<template>
<v-container class="fill-height">
<v-btn @click="clickedAsync">Click Async</v-btn>
<v-btn @click="clickedThen">Click Then</v-btn>
</v-container>
</template>
<script setup>
import { useDialog } from '@/composable/useDialog';
const clickedAsync = async () => {
const response = await useDialog({ message: "this works very nice !" });
if (response) {
alert("Dialog confirmed " + response,)
} else {
alert("Dialog canceled " + response, response)
}
}
const clickedThen = () => {
useDialog({ message: "this works very nice !" }).then(response=>{
if (response) {
alert("Dialog confirmed " + response,)
} else {
alert("Dialog canceled " + response, response)
}
})
}
</script>
Dialogs are essential for displaying critical information, confirmations, or forms without leaving the current page. However, managing dialogs can become cumbersome, especially in large-scale applications. Programmatic dialogs help mitigate this by creating dialogs on the fly using JavaScript, making them more manageable and reducing template bloat. Composable dialogs are built using the Composition API in Vue, enabling the encapsulation of dialog-related logic in a reusable and maintainable way.