To download this project, clone it from my Github repo.
I am using Vue JS 3, and I found that the documentation of Bootstrap could not help me use modals in my Vue.js project. The problem is that the documentation at Bootstrap 5’s site is cryptic about toggling the modal without using a button. It talks of using:
var myModal = new bootstrap.Modal(document.getElementById('myModal'), options)
But I couldnt import bootstrap into my project. Perhaps this was because I was using the CDN version instead of self hosting it.
It’s easy to implement this once you understand how Bootstrap modals work. Bootstrap modals have a div element with a class of modal fade
. When it is triggered, this element gets the show
attribute (not a class), and d-block
class as well. In addition, the body tag gets an additional class of modal-open
. When the modal is closed, this process is reversed. Understanding this, we can easily implement Bootstrap 5 modals in one’s code:
Import Bootstrap 5’s CDN in your code. Add both the CSS and JS to your code.
Our sample Single Page Component will look like this:
Template:
<template>
<div>
<p>Test modal<a href="#" @click="modalToggle">now</a></p>
<div>
<button type="button" class="btn btn-primary" @click="modalToggle">My Modal</button>
<div
ref="modal"
class="modal fade"
:class="{ show: active, 'd-block': active }"
tabindex="-1"
role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
@click="modalToggle">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
</div>
</div>
</div>
<div v-if="active" class="modal-backdrop fade show"></div>
</div>
</div>
</template>
Script:
<script>
export default {
data() {
return {
active: false,
}
},
methods: {
modalToggle() {
const body = document.querySelector("body")
this.active = !this.active
this.active ? body.classList.add("modal-open") : body.classList.remove("modal-open")
},
},
}
</script>
Here, we have a variable active
which is initially set false. So modal will not show up on page load. On clicking a link, we use a method to toggle this variable. This will remove the show attribute and the d-block class from our modalm and remove the modal-open
property from the body tag.
Using Bootstrap modals when the modal is implemented as a Child Component.
Let’s assume we have a parent component, which will use the BootstrapModal as a component. That’s a very common scenario.
Parent:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h3>Test Bootstrap Modal</h3>
<bootstrap-modal :showModal="showModalNow" @closeModal="closeMyModal"></bootstrap-modal>
<a href="#" @click="toggleModal">now</a>
</div>
</template>
So, we are adding the modal as a component. It will be turned on by setting our variable showModalNow to true. It can be closed by clicking the close button on the opened modal.
<script>
import BootstrapModal from "./BootstrapModal.vue"
export default {
components: {
"bootstrap-modal": BootstrapModal,
},
data() {
return {
showModalNow: false,
}
},
methods: {
closeMyModal() {
this.showModalNow = false;
},
toggleModal() {
this.showModalNow = !this.showModalNow;
}
}
}
</script>
Now the child component
<template>
<teleport to="body">
<div
ref="modal"
class="modal fade"
:class="{ show: active, 'd-block': active }"
tabindex="-1"
role="dialog"
>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header bg-primary text-light">
<h5 class="modal-title">Modal title</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
v-on:click="$emit('closeModal')"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body bg-success text-dark">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer bg-warning text-dark">
<button type="button" class="btn btn-secondary" v-on:click="$emit('closeModal')">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</teleport>
</template>
<script>
export default {
name: "BootstrapModal",
emits: ["closeModal"],
props: {
showModal: Boolean,
},
watch: {
showModal: {
handler(newVal) {
this.active = newVal;
const body = document.querySelector("body");
this.showModal ? body.classList.add("modal-open") : body.classList.remove("modal-open")
},
immediate: true,
deep: true,
},
},
data() {
return {
active: this.showModal,
};
},
};
</script>
References:
Joel G Mathew, known in tech circles by the pseudonym Droidzone, is an opensource and programming enthusiast.
He is a full stack developer, whose favorite languages are currently Python and Vue.js. He is also fluent in Javascript, Flutter/Dart, Perl, PHP, SQL, C and bash shell scripting. He loves Linux, and can often be found tinkering with linux kernel code, and source code for GNU applications. He used to be an active developer on XDA forums, and his tinkered ROMS used to be very popular in the early 2000s.
His favorite pastime is grappling with GNU compilers, discovering newer Linux secrets, writing scripts, hacking roms, and programs (nothing illegal), reading, blogging. and testing out the latest gadgets.
When away from the tech world, Dr Joel G. Mathew is a practising ENT Surgeon, busy with surgeries and clinical practise.