OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

Pressing Escape key on modal triggers the escape event on the parent component

  • Thread starter Thread starter Vikas Jyani
  • Start date Start date
V

Vikas Jyani

Guest
This is the main page.

Code:
"use client";

import React, { useEffect, useState } from "react";
import TestModal from "./TestModal";

const App = () => {
  const [isOpen, setIsOpen] = useState(false);
  const [isDiscardModalOpen, setIsDiscardModalOpen] = useState(false);

  useEffect(() => {
    const handleEscape = (event: KeyboardEvent) => {
      if (event.key === "Escape" && !isDiscardModalOpen) {
        setIsDiscardModalOpen(true);
      }
    };

    document.addEventListener("keydown", handleEscape);

    return () => {
      document.removeEventListener("keydown", handleEscape);
    };
  }, [isDiscardModalOpen]);

  return (
    <div>
      <button onClick={() => setIsOpen(true)}>Open Modal</button>
      <TestModal
        title="Test Modal"
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
      >
        <div>This is a test Modal</div>
      </TestModal>
      <TestModal
        title="Discard Modal"
        isOpen={isDiscardModalOpen}
        onClose={() => {
          setIsDiscardModalOpen(false);
        }}
      >
        <div>This is a discard Modal</div>
      </TestModal>
    </div>
  );
};

export default App;

This is a modal component.

Code:
"use client";

import React, { useEffect, useRef } from "react";

interface ModalProps {
  isOpen: boolean;
  title: string;
  children: React.ReactNode;
  onClose: () => void;
}

const TestModal: React.FC<ModalProps> = ({
  isOpen,
  title,
  children,
  onClose,
}) => {
  const modalRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      if (
        isOpen &&
        modalRef.current &&
        !modalRef.current.contains(event.target as Node)
      ) {
        event.preventDefault();
      }
    };

    const handleEscape = (event: KeyboardEvent) => {
      if (event.key === "Escape" && isOpen) {
        onClose();
      }
    };

    if (isOpen) {
      document.addEventListener("keydown", handleKeyDown);
      document.addEventListener("keydown", handleEscape);
    }

    return () => {
      document.removeEventListener("keydown", handleKeyDown);
      document.removeEventListener("keydown", handleEscape);
    };
  }, [isOpen, onClose]);

  if (!isOpen) return null;

  return (
    <>
      <div
        role="dialog"
        aria-modal="true"
        ref={modalRef}
        className="fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center p-4"
      >
        <div className="bg-white p-6 rounded-lg shadow-lg max-w-lg w-full">
          <header className="flex justify-between items-center mb-4">
            <h2 className="text-xl font-semibold">{title}</h2>
            <button
              onClick={onClose}
              className="text-gray-600 hover:text-gray-800"
            >
              Close
            </button>
          </header>
          <div className="modal-content overflow-auto max-h-[80vh]">
            {children}
          </div>
        </div>
      </div>
    </>
  );
};

export default TestModal;

I have a page and a TestModal component. I have a esc button functionality on my page where hitting the esc opens the discard modal. And I also have a escape functionality in the testModal component. When the modal is open, hitting esc closes the modal. The problem that I am having is that when the modal is open and I hit the esc key, the esc button event on the page triggers on top of the modal esc event. So now there are two modals open and the discard modal is open on top of the testModal. It shouldn't be happening. Hitting the esc key from the modal should only close the modal and not progagate the click event to the parent. How can I make it so that when a modal is open, all the keyboard and mouse events are disabled for its all parent components?

Try it yourself for better context: CodesandboxLink

<p><strong>This is the main page.</strong></p>
<pre><code>"use client";

import React, { useEffect, useState } from "react";
import TestModal from "./TestModal";

const App = () => {
const [isOpen, setIsOpen] = useState(false);
const [isDiscardModalOpen, setIsDiscardModalOpen] = useState(false);

useEffect(() => {
const handleEscape = (event: KeyboardEvent) => {
if (event.key === "Escape" && !isDiscardModalOpen) {
setIsDiscardModalOpen(true);
}
};

document.addEventListener("keydown", handleEscape);

return () => {
document.removeEventListener("keydown", handleEscape);
};
}, [isDiscardModalOpen]);

return (
<div>
<button onClick={() => setIsOpen(true)}>Open Modal</button>
<TestModal
title="Test Modal"
isOpen={isOpen}
onClose={() => setIsOpen(false)}
>
<div>This is a test Modal</div>
</TestModal>
<TestModal
title="Discard Modal"
isOpen={isDiscardModalOpen}
onClose={() => {
setIsDiscardModalOpen(false);
}}
>
<div>This is a discard Modal</div>
</TestModal>
</div>
);
};

export default App;
</code></pre>
<p><strong>This is a modal component.</strong></p>
<pre><code>"use client";

import React, { useEffect, useRef } from "react";

interface ModalProps {
isOpen: boolean;
title: string;
children: React.ReactNode;
onClose: () => void;
}

const TestModal: React.FC<ModalProps> = ({
isOpen,
title,
children,
onClose,
}) => {
const modalRef = useRef<HTMLDivElement>(null);

useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (
isOpen &&
modalRef.current &&
!modalRef.current.contains(event.target as Node)
) {
event.preventDefault();
}
};

const handleEscape = (event: KeyboardEvent) => {
if (event.key === "Escape" && isOpen) {
onClose();
}
};

if (isOpen) {
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("keydown", handleEscape);
}

return () => {
document.removeEventListener("keydown", handleKeyDown);
document.removeEventListener("keydown", handleEscape);
};
}, [isOpen, onClose]);

if (!isOpen) return null;

return (
<>
<div
role="dialog"
aria-modal="true"
ref={modalRef}
className="fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center p-4"
>
<div className="bg-white p-6 rounded-lg shadow-lg max-w-lg w-full">
<header className="flex justify-between items-center mb-4">
<h2 className="text-xl font-semibold">{title}</h2>
<button
onClick={onClose}
className="text-gray-600 hover:text-gray-800"
>
Close
</button>
</header>
<div className="modal-content overflow-auto max-h-[80vh]">
{children}
</div>
</div>
</div>
</>
);
};

export default TestModal;
</code></pre>
<p>I have a page and a TestModal component. I have a esc button functionality on my page where hitting the esc opens the discard modal. And I also have a escape functionality in the testModal component. When the modal is open, hitting esc closes the modal. The problem that I am having is that when the modal is open and I hit the esc key, the esc button event on the page triggers on top of the modal esc event. So now there are two modals open and the discard modal is open on top of the testModal. It shouldn't be happening. Hitting the esc key from the modal should only close the modal and not progagate the click event to the parent. How can I make it so that when a modal is open, all the keyboard and mouse events are disabled for its all parent components?</p>
<p>Try it yourself for better context:
<a href="https://codesandbox.io/p/sandbox/mo...ar%22%3Atrue%2C%22sidebarPanelSize%22%3A15%7D" rel="nofollow noreferrer">CodesandboxLink</a></p>
 

Latest posts

A
Replies
0
Views
1
Ashrik Ahamed
A
A
Replies
0
Views
1
Ashrik Ahamed
A

Online statistics

Members online
1
Guests online
4
Total visitors
5
Top