Tailwind dynamic modal with javascript
Check the code
<!-- Button to Open Modal -->
<button class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors duration-200" data-modal="exampleModal">
Open Modal
</button>
<!-- Modal -->
<div id="exampleModal" class="fixed inset-0 hidden opacity-0 bg-black bg-opacity-50 flex items-center justify-center p-4 transition-opacity duration-200" aria-hidden="true" aria-labelledby="modalTitle" aria-describedby="modalDescription">
<div class="bg-white p-6 rounded-lg shadow-lg w-full max-w-md">
<!-- Modal Header -->
<div class="flex justify-between items-center border-b pb-2">
<h2 id="modalTitle" class="text-lg font-semibold">Modal Title</h2>
<button class="text-gray-500 hover:text-gray-700 close-modal" aria-label="Close modal">×</button>
</div>
<!-- Modal Body -->
<div class="py-4">
<p id="modalDescription" class="text-gray-700">This is a simple modal using Tailwind CSS.</p>
</div>
<!-- Modal Footer -->
<div class="flex justify-end gap-2 mt-4 border-t pt-2">
<button class="px-4 py-2 bg-gray-300 text-gray-700 rounded hover:bg-gray-400 transition-colors duration-200 close-modal">Close</button>
<button class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors duration-200">Save Changes</button>
</div>
</div>
</div>
<script>
class CustomModal {
constructor(modalId) {
this.modal = document.getElementById(modalId);
if (!this.modal) {
throw new Error(`Modal with ID "${modalId}" not found.`);
}
this.closeButtons = this.modal.querySelectorAll(".close-modal");
this.initEvents();
}
open() {
this.modal.classList.remove("hidden"); // Remove hidden class
setTimeout(() => {
this.modal.classList.remove("opacity-0"); // Fade in
}, 10); // Small delay to allow display change
document.body.style.overflow = "hidden"; // Prevent scrolling
this.modal.setAttribute("aria-hidden", "false"); // Update ARIA attribute
}
close() {
this.modal.classList.add("opacity-0"); // Fade out
setTimeout(() => {
this.modal.classList.add("hidden"); // Hide after transition
}, 200); // Match transition duration
document.body.style.overflow = "auto"; // Restore scrolling
this.modal.setAttribute("aria-hidden", "true"); // Update ARIA attribute
}
initEvents() {
// Close modal when clicking on close buttons
this.closeButtons.forEach(button => {
button.addEventListener("click", () => this.close());
});
// Close modal when clicking outside the modal
window.addEventListener("click", (e) => {
if (e.target === this.modal) {
this.close();
}
});
// Close modal when pressing the Escape key
window.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
this.close();
}
});
}
}
// Global modal handler
const modals = {};
// Initialize modals after the DOM is fully loaded
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll("[data-modal]").forEach(button => {
const modalId = button.getAttribute("data-modal");
if (!modals[modalId]) {
modals[modalId] = new CustomModal(modalId);
}
button.addEventListener("click", () => modals[modalId].open());
});
});
</script>