Skip to content

Commit 3fb3a74

Browse files
committed
Prevent body scolling when modal is open.
1 parent 8464089 commit 3fb3a74

File tree

1 file changed

+58
-6
lines changed

1 file changed

+58
-6
lines changed

src/components/Modal.astro

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,61 @@ const { id = 'modal', open = false, closeOnOutsideClick = false } = Astro.props;
2727
</div>
2828
<script is:inline>
2929
document.addEventListener('DOMContentLoaded', () => {
30+
// Function to toggle body scroll
31+
const toggleBodyScroll = (disable) => {
32+
if (disable) {
33+
// Save the current scroll position
34+
const scrollY = window.scrollY;
35+
document.body.style.position = 'fixed';
36+
document.body.style.top = `-${scrollY}px`;
37+
document.body.style.width = '100%';
38+
document.body.dataset.scrollPosition = scrollY.toString();
39+
} else {
40+
// Restore scroll position
41+
const scrollY = parseInt(document.body.dataset.scrollPosition || '0');
42+
document.body.style.position = '';
43+
document.body.style.top = '';
44+
document.body.style.width = '';
45+
window.scrollTo(0, scrollY);
46+
delete document.body.dataset.scrollPosition;
47+
}
48+
};
49+
50+
// Function to open modal
51+
const openModal = (modal) => {
52+
if (modal) {
53+
// Disable body scroll
54+
toggleBodyScroll(true);
55+
// Show modal
56+
modal.classList.remove('opacity-0', 'invisible');
57+
modal.classList.add('opacity-100', 'visible');
58+
}
59+
};
60+
61+
// Function to close modal
62+
const closeModal = (modal) => {
63+
if (modal) {
64+
// Enable body scroll
65+
toggleBodyScroll(false);
66+
// Hide modal
67+
modal.classList.remove('opacity-100', 'visible');
68+
modal.classList.add('opacity-0', 'invisible');
69+
}
70+
};
71+
3072
// Open modal buttons
3173
document.querySelectorAll('[data-open-modal]').forEach(button => {
3274
button.addEventListener('click', () => {
3375
const modal = document.getElementById(button.dataset.openModal);
34-
modal?.classList.remove('opacity-0', 'invisible');
35-
modal?.classList.add('opacity-100', 'visible');
76+
openModal(modal);
3677
});
3778
});
3879

3980
// Close modal buttons
4081
document.querySelectorAll('[data-close-modal]').forEach(button => {
4182
button.addEventListener('click', () => {
4283
const modal = button.closest('[data-modal-wrapper]');
43-
modal?.classList.remove('opacity-100', 'visible');
44-
modal?.classList.add('opacity-0', 'invisible');
84+
closeModal(modal);
4585
});
4686
});
4787

@@ -53,11 +93,23 @@ const { id = 'modal', open = false, closeOnOutsideClick = false } = Astro.props;
5393
modal.addEventListener('click', (event) => {
5494
// Check if the click was on the wrapper but not on the content
5595
if (event.target === modal) {
56-
modal.classList.remove('opacity-100', 'visible');
57-
modal.classList.add('opacity-0', 'invisible');
96+
closeModal(modal);
5897
}
5998
});
6099
}
100+
101+
// Initialize any modal that's set to open by default
102+
if (modal.classList.contains('opacity-100') && modal.classList.contains('visible')) {
103+
toggleBodyScroll(true);
104+
}
105+
});
106+
107+
// Handle escape key to close all modals
108+
document.addEventListener('keydown', (event) => {
109+
if (event.key === 'Escape') {
110+
const visibleModals = document.querySelectorAll('[data-modal-wrapper].visible, [data-modal-wrapper].opacity-100');
111+
visibleModals.forEach(modal => closeModal(modal));
112+
}
61113
});
62114
});
63115
</script>

0 commit comments

Comments
 (0)