A Vue 3 component using the native <dialog>
element. This e.g. provides more helpful events than <dialog/>
itself.
This library also allows to imperatively show dialogs using a useDialog()
composition function and (optionally) have dialogs "return" result values.
See the interactive StoryBook page and the documentation further down on this page.
npm install v-native-dialog
pnpm add v-native-dialog
<script type="setup">
import { ref } from 'vue';
import { NativeDialog } from 'v-native-dialog';
const open = ref(true);
</script>
<template>
<!-- ... other content ... -->
<NativeDialog v-model:open="open" v-slot="{ closeDialog }">
<p>The dialog content</p>
<button type="button" @click="closeDialog('ok')">OK</button>
<button type="button" @click="closeDialog('cancel')">Cancel</button>
</NativeDialog>
</template>
<style>
@import "v-native-dialog/style.css";
</style>
You can render dialogs on the fly using useDialog()
without including the dialog content in a parent Vue component. This allows to extract reusable dialogs.
Prerequisite: Render <DynamicDialogOutlet/>
provided by this library somewhere in you app. This renders all dynamic dialogs.
// some-file.ts
import NumberDialog from "./number-dialog.vue";
async function askUser(question: string): Promise<number> {
const { resultPromise } = useDialog(NumberDialog, { props: { question } });
const { action, result } = await resultPromise;
if (action == "ok") {
return result;
} else {
// action is 'close' or 'cancel'
return -1;
}
// alternatively: return result ?? -1;
}
<!-- number-dialog.vue -->
<script setup lang="ts">
import NativeDialog from "../native-dialog.vue";
import { ref } from "vue";
defineProps<{ question: string }>();
const number = ref(42);
</script>
<template>
<NativeDialog v-slot="{ closeDialog }">
<p>{{ question }}</p>
<p>
<input type="number" v-model="number" />
</p>
<button type="button" @click="closeDialog('ok', number)">OK</button>
<button type="button" @click="closeDialog('cancel')">Cancel</button>
</NativeDialog>
</template>
- Type:
boolean
- Default:
false
, i.e. modal - Description: If
true
, the dialog will [https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/show](not be modal).
- Type:
boolean
- Default:
false
- Description: If
true
, prevents the dialog from being closed using the 'esc' key (or other platform ways of closing dialogs). Some browsers allow this only a single time, then close anyway. Use this sparingly, to provide a good user experience.
- Type:
string
("if"
|"show"
) - Default:
"if"
- Description: How the dialog shall be shown/hidden. By default, uses
v-if
, i.e., no rendering if hidden, re-rendering on show. If set to'show'
, the rendered dialog is always in the DOM and will be shown/hidden using the'open'
attribute.
- Slot Props:
closeDialog
: Function to close the dialog and optionally provide theaction
andresult
for theresult
event.
- Description: Triggers when the dialog is shown.
- Payload:
dialog
:HTMLDialogElement
- Description: Triggers when the dialog has closed.
- Payload:
dialog
:HTMLDialogElement | null
-
Description: Triggers when a result is emitted from the dialog (using
closeDialog()
). -
Payload:
-
payload
:{action: string, result?: any}
akaResultPayload
-
action
is'close'
by default, but can be any string you specify in thecloseDialog(action)
call, e.g.'ok'
or'cancel'
.If closed via
v-model:open
the action is'hide'
. -
result
isundefined
by default. You can specify the value using thecloseDialog(action, result)
call. Use this for the "return value" of the dialog.
-
-
Can be adapted using CSS.
- Default:
#fff
- Description: Background color for the dialog content.
- Default:
rgba(0, 0, 0, 0.1)
- Description: Color of the backdrop behind the dialog overlaying the page content.
- Default:
1rem
- Description: Padding for the dialog content.
useDialog()
creates (and by default opens) a dialog dynamically by adding it to the dialog list. This dialog list is rendered using the DynamicDialogOutlet
component.
See Usage above.
component
(Component
): A Vue component that uses theNativeDialog
in its template.options
(Object
, optional):initiallyOpen
(Boolean
, default:true
): Determines if the dialog should be open initially.removeAfterClose
(Boolean
, default:true
): Determines if the dialog should be removed from the dynamic list after it is closed. If you want to be able to re-open the dialog, set this tofalse
.props
(Record<string, any>, default:{}
): Props to pass to the dynamic dialogcomponent
.dynamicDialogs
(Ref<DialogInfo[]>, default: built-in global list): The list of dynamic dialogs.
result
(Ref<ResultPayload<R> | undefined>
): Aref
holding the result payload of the dialog.resultPromise
(Promise<ResultPayload<R>>
): APromise
that resolves with the result payload (close action and result) when the dialog is closed. Mostly helpful for one-shot dialogs.show
(Function
): Opens the dialog.close
(Function
): Closes the dialog.destroy
(Function
): Closes the dialog and removes it from the dialog list. The dialog cannot be re-opened after this.
This component should be rendered somewhere in your app. This is required for dialogs created dynamically using useDialog()
to be shown.
- Component
vue3-native-dialog
- Article 'Building a dialog component'
- Remaining caveats of the
<dialog>
element
Run the interactive demo, which works as a nice testbed for changes.
npm run storybook