Skip to content

Commit b971bc8

Browse files
committed
finished adding scroll locking when the modal is active
1 parent a3484fe commit b971bc8

File tree

1 file changed

+57
-4
lines changed

1 file changed

+57
-4
lines changed

src/components/Projects.jsx

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,15 +215,62 @@ const Projects = () => {
215215
const sectionRef = useRef(null);
216216
const modalRef = useRef(null);
217217

218+
// Add scroll lock effect
219+
useEffect(() => {
220+
const body = document.body;
221+
if (modalOpen) {
222+
// Store current scroll position
223+
const scrollY = window.scrollY;
224+
body.style.position = 'fixed';
225+
body.style.width = '100%';
226+
body.style.top = `-${scrollY}px`;
227+
// Add class to prevent background interactions
228+
body.classList.add('modal-open');
229+
} else {
230+
// Restore scroll position
231+
const scrollY = body.style.top;
232+
body.style.position = '';
233+
body.style.top = '';
234+
body.style.width = '';
235+
window.scrollTo(0, parseInt(scrollY || '0') * -1);
236+
// Remove class preventing background interactions
237+
body.classList.remove('modal-open');
238+
}
239+
}, [modalOpen]);
240+
241+
// Handle keyboard interactions
218242
useEffect(() => {
219243
const handleKeyDown = (event) => {
220244
if (event.key === 'Escape') {
221245
closeModal();
246+
} else if (event.key === 'Tab' && modalOpen) {
247+
// Get all focusable elements in modal
248+
const focusableElements = modalRef.current?.querySelectorAll(
249+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
250+
);
251+
252+
if (focusableElements?.length) {
253+
const firstElement = focusableElements[0];
254+
const lastElement = focusableElements[focusableElements.length - 1];
255+
256+
// If shift+tab and first element is focused, move to last element
257+
if (event.shiftKey && document.activeElement === firstElement) {
258+
event.preventDefault();
259+
lastElement.focus();
260+
}
261+
// If tab and last element is focused, move to first element
262+
else if (!event.shiftKey && document.activeElement === lastElement) {
263+
event.preventDefault();
264+
firstElement.focus();
265+
}
266+
}
222267
}
223268
};
224269

225270
if (modalOpen) {
226271
window.addEventListener('keydown', handleKeyDown);
272+
// Focus the modal when it opens
273+
modalRef.current?.focus();
227274
} else {
228275
window.removeEventListener('keydown', handleKeyDown);
229276
}
@@ -304,7 +351,7 @@ const Projects = () => {
304351
id="projects"
305352
>
306353
<GradientHeading visibleSection={visibleSection}>
307-
Featured Projects
354+
Featured Projects
308355
</GradientHeading>
309356

310357
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 max-w-7xl mx-auto">
@@ -396,15 +443,21 @@ const Projects = () => {
396443
onClick={closeModal}
397444
ref={modalRef}
398445
tabIndex="-1"
446+
role="dialog"
447+
aria-modal="true"
448+
aria-labelledby="modal-title"
399449
>
400450
<div
401451
className={`modal-content ${modalOpen ? 'open' : ''}`}
402452
onClick={(e) => e.stopPropagation()}
403-
tabIndex="-1"
404453
>
405454
<div className="modal-header">
406-
<h3 className="modal-title">{selectedProject.title}</h3>
407-
<button className="modal-close" onClick={closeModal}>
455+
<h3 className="modal-title" id="modal-title">{selectedProject.title}</h3>
456+
<button
457+
className="modal-close"
458+
onClick={closeModal}
459+
aria-label="Close modal"
460+
>
408461
×
409462
</button>
410463
</div>

0 commit comments

Comments
 (0)