Kamu lagi bangun modal, dropdown, atau menu. Mau tutup kalau user klik di luar. Ini cara bersih untuk melakukannya.
Konsepnya
Pakai Node.contains() untuk cek apakah elemen yang diklik ada di dalam elemen target kamu. Kalau tidak — berarti user klik di luar.
Implementasi dasar
import { useEffect, useRef } from 'react';
function Modal({ isOpen, onClose, children }) {
const modalRef = useRef<HTMLDivElement>(null);
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (modalRef.current && !modalRef.current.contains(event.target as Node)) {
onClose();
}
}
if (isOpen) {
document.addEventListener('mousedown', handleClickOutside);
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div ref={modalRef} className="modal">
{children}
</div>
);
}
Cara kerjanya
modalRef.currentmenunjuk ke elemen modal kamuevent.targetadalah apa yang di-klik usercontains()returntruekalau elemen yang diklik ada di dalam modal- Kalau return
false— klik di luar, jadi tutup modalnya
Handle device touch
Tambah touchstart untuk mobile:
useEffect(() => {
function handleClickOutside(event: MouseEvent | TouchEvent) {
if (modalRef.current && !modalRef.current.contains(event.target as Node)) {
onClose();
}
}
if (isOpen) {
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener('touchstart', handleClickOutside);
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('touchstart', handleClickOutside);
};
}, [isOpen, onClose]);
Jangan close saat klik di dalam
Check !modalRef.current.contains(event.target) sudah handle ini — klik di dalam modal diabaikan.
Selesai. Satu ref, satu useEffect, dan modal kamu tutup kalau user klik di mana pun di luar.