Skip to content

Instantly share code, notes, and snippets.

@calvinjuarez
Last active December 13, 2023 22:28
Show Gist options
  • Save calvinjuarez/b754b67b6f6d0c05e3e65137d6e5411a to your computer and use it in GitHub Desktop.
Save calvinjuarez/b754b67b6f6d0c05e3e65137d6e5411a to your computer and use it in GitHub Desktop.
Vue 3 `<dialog>`-based Modal Component (Bootstrap-friendly)

Vue 3 <dialog>-based Modal Component (Bootstrap-friendly)

A simple Vue 3 <Transition> wrapper around the native <dialog> element that can take advantage of Bootstrap's .modal CSS styles. The component exposes 4 events, show, shown, close, and closed (borrowing names from Bootstrap).

Example:

<Modal ref="$modal" @closed="doSomethingOnClosed">
	<header class="modal-header">
		<h2>My Modal</h2>
		<button
			type="button"
			class="btn-close"
			aria-label="Close"
			@click="$modal.close"
		></button>
	</header>
	<div class="modal-body">
		<!-- ... -->
	</div>
	<div class="modal-footer">
		<button type="button" class="btn btn-secondary" @click="$modal.close">Close</button>
		<button type="button" class="btn btn-primary" @click="doSomething">Save</button>
	</div>
</Modal>
<script setup>
import { ref } from 'vue';
const $dialog = ref(null);
const showing = ref(false);
function close() { showing.value = false; }
function show() { showing.value = true; }
defineExpose({
close,
show,
});
</script>
<template>
<Transition
@before-enter="$emit('show');$dialog.showModal();"
@after-enter="$emit('shown');"
@before-leave="$emit('close');"
@after-leave="$dialog.close();$emit('closed');"
>
<dialog
class="modal"
@click="close"
ref="$dialog"
v-show="showing"
>
<form
method="dialog"
class="modal-content"
@click.stop
>
<slot></slot>
</form>
</dialog>
</Transition>
</template>
<style>
.modal:modal {
position: fixed;
height: fit-content;
width: fit-content;
background: none;
border: none;
overflow-x: auto;
overflow-y: auto;
}
.modal[open] {
display: block;
}
.v-enter-active,
.v-leave-active {
transition: opacity 0.2s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment