v-native-dialog
v1.0.1
Published
A Vue 3 component using the native <dialog> element
Downloads
167
Maintainers
Readme
v-native-dialog
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.
Docs
See the interactive StoryBook page and the documentation further down on this page.
Install
npm install v-native-dialog
pnpm add v-native-dialog
Usage
As a child Vue component
<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>
As a dynamic dialog
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>
Docs: NativeDialog
component
Props
nonModal
- 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).
preventEscape
- 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.
displayDirective
- 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.
Default Slot
- Slot Props:
closeDialog
: Function to close the dialog and optionally provide theaction
andresult
for theresult
event.
Events
opened
- Description: Triggers when the dialog is shown.
- Payload:
dialog
:HTMLDialogElement
closed
- Description: Triggers when the dialog has closed.
- Payload:
dialog
:HTMLDialogElement | null
result
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.
CSS custom properties
Can be adapted using CSS.
--v-native-dialog-bg-color
- Default:
#fff
- Description: Background color for the dialog content.
--v-native-dialog-backdrop
- Default:
rgba(0, 0, 0, 0.1)
- Description: Color of the backdrop behind the dialog overlaying the page content.
--v-native-dialog-spacing
- Default:
1rem
- Description: Padding for the dialog content.
Docs: useDialog
composition function
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.
Parameters
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.
Returns
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.
Docs: DynamicDialogOutlet
component
This component should be rendered somewhere in your app. This is required for dialogs created dynamically using useDialog()
to be shown.
Additional resources
Inspirations
- Component
vue3-native-dialog
- Article 'Building a dialog component'
Misc
- Remaining caveats of the
<dialog>
element
Contribute
Run the interactive demo, which works as a nice testbed for changes.
npm run storybook