DEV Community

Cover image for React modal using html "div"
Ellis
Ellis

Posted on • Updated on

React modal using html "div"

The goal:

Notes:

  • The "Modal" component is generic, it shows content from the parent container, provided as children.
  • preventAutoClose() prevents closing when we click inside the modal dialog box.

I created two components:

First, the "DivModalTester" component contains and opens the modal:

import { useState } from "react";

// @ts-ignore
import { DivModal } from "components";

const DivModalTester = () => {
  const [isOpened, setIsOpened] = useState(false);

  const onProceed = () => {
    console.log("Proceed clicked");
  };

  return (
    <div>
      <button onClick={() => setIsOpened(true)}>Open "div" modal</button>

      <DivModal
        title="Dialog modal example"
        isOpened={isOpened}
        onProceed={onProceed}
        onClose={() => setIsOpened(false)}
      >
        <p>To close: click Close, press Escape, or click outside.</p>
      </DivModal>
    </div>
  );
};

export default DivModalTester;
Enter fullscreen mode Exit fullscreen mode

Secondly, the "DivModal" component itself:

import styled from "styled-components";

// @ts-ignore
import useKeyDown from "hooks/useKeyDown";

const Overlay = styled.div`
  z-index: 1;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.3);
`;

const Container = styled.div`
  z-index: 2;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 400px;
  border-radius: 8px;
  border: 1px solid #888;
  padding: 20px;
  background-color: white;
`;

const Buttons = styled.div`
  display: flex;
  justify-content: space-between;
`;

type Props = {
  title: string;
  isOpened: boolean;
  onProceed: () => void;
  onClose: () => void;
  children: React.ReactNode;
};

const DivModal = ({ title, isOpened, onProceed, onClose, children }: Props) => {
  useKeyDown("Escape", onClose);

  const proceedAndClose = () => {
    onProceed();
    onClose();
  };

  const preventAutoClose = (e: React.MouseEvent) => e.stopPropagation();

  if (!isOpened) return null;

  return (
    <Overlay onClick={onClose}>
      <Container onClick={preventAutoClose}>
        <h3>{title}</h3>

        {children}

        <Buttons>
          <button onClick={proceedAndClose}>Proceed</button>
          <button onClick={onClose}>Close</button>
        </Buttons>
      </Container>
    </Overlay>
  );
};

export default DivModal;
Enter fullscreen mode Exit fullscreen mode

Additionally, the modal component is using the useKeyDown() hook, to close when Escape is pressed, as given here: React hook: useKeyDown()

Thanks for reading. Suggestions/corrections are welcome.

Top comments (0)