Trying to develop a reusable Modal Component using Bootstrap 5, Vuejs 3, and composible API. I have managed to achieve partial functionality,
Provided (Basic Bootstrap 5 modal with classes added based on the 'show' prop, and slots in the body and footer):
<script setup lang="ts">
defineProps({
show: {
type: Boolean,
default: false,
},
title: {
type: String,
default: "<<Title goes here>>",
},
});
</script>
<template>
<div class="modal fade" :class="{ show: show, 'd-block': show }"
id="exampleModal" tabindex="-1" aria-labelledby="" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{{ title }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<slot name="body" />
</div>
<div class="modal-footer">
<slot name="footer" />
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
Close
</button>
</div>
</div>
</div>
</div>
</template>
and being triggered by
<script setup lang="ts">
import { ref } from "vue";
import Modal from "@/components/Common/Modal.vue";
let modalVisible = ref(false);
function showModal(){
modalVisible.value = true;
}
</script>
<template>
<button @click="showModal">Show Modal</button>
<Modal title="Model title goes here" :show="modalVisible">
<template #body>This content goes in the body</template>
<template #footer>
<button class="btn btn-primary">Extra footer button</button>
</template>
</Modal>
</template>
The modal is displayed but the fade-in animation isn't working, the backdrop isn't visible, and the buttons in the modal don't function (i.e., it won't close). There seems to be an issue with my overall approach.
https://i.sstatic.net/wgF75.png
NOTE. I can't use a standard button with
data-bs-toggle="modal" data-bs-target="#exampleModal"
attributes as the actual trigger for this model originates from the logic of another component (just setting a boolean), and the reusable modal component will be independent of its trigger --- it also doesn't seem like the proper 'Vue' way to do it.
It feels like I'm just displaying the HTML and need to somehow instantiate a bootstrap modal... I'm just not sure how to approach it
package.json (relevant dependencies)
"dependencies": {
"@popperjs/core": "^2.11.2",
"bootstrap": "^5.1.3",
"vue": "^3.2.31",
},
Code sandbox here (I couldn't get the new Composition API and TS to work on CodeSandbox, so it's a slight rewrite using the standard Options API approach, resulting in slightly different code behavior)