<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Daniel Rivas</title>
    <description>The latest articles on DEV Community by Daniel Rivas (@djra26111990).</description>
    <link>https://dev.to/djra26111990</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F737328%2Fa3655397-bf42-4efc-90ff-84e3dc21545d.png</url>
      <title>DEV Community: Daniel Rivas</title>
      <link>https://dev.to/djra26111990</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/djra26111990"/>
    <language>en</language>
    <item>
      <title>React Portals: create and open modals with keyboard keys</title>
      <dc:creator>Daniel Rivas</dc:creator>
      <pubDate>Sun, 03 Apr 2022 04:30:27 +0000</pubDate>
      <link>https://dev.to/djra26111990/react-portals-create-and-open-modals-with-keyboard-keys-1gc2</link>
      <guid>https://dev.to/djra26111990/react-portals-create-and-open-modals-with-keyboard-keys-1gc2</guid>
      <description>&lt;p&gt;Hi there!&lt;/p&gt;

&lt;p&gt;In this post we will create the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdet2nx2ml49yirtdcipu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdet2nx2ml49yirtdcipu.png" alt="Running app when loaded is complete"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpy28gln7ri1zwueeez4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpy28gln7ri1zwueeez4.png" alt="Modal opened when press the button or press down any F1 to F3 keys"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we finished to build this app, it will be look like this.&lt;/p&gt;

&lt;p&gt;The goal when building this app is to provide a mechanism to open a modal pressing the button on the screen or when we press F1 to F3 keys of ours keyboards to achieve the same objective.&lt;/p&gt;

&lt;p&gt;To begin with, i've use vite to build this project, but you can use any other tools like create-react-app or build from scratch using webpack and react.&lt;/p&gt;

&lt;p&gt;This project was made using TypeScript and Material-UI to not begin from scratch styling our components.&lt;/p&gt;

&lt;p&gt;First, we need to know what a React portal is.&lt;/p&gt;

&lt;p&gt;React docs says:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Normally, when you return an element from a component’s render method when you have an class component or when you return JSX using functional component, it’s mounted into the DOM as a child of the nearest parent node. However, sometimes it’s useful to insert a child into a different location in the DOM&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Basically it is here when the React Portals come to the rescue.&lt;/p&gt;

&lt;p&gt;Here you can find the full code here in this Github &lt;a href="https://github.com/djra26111990/react-ts-keyevent-modal-portals" rel="noopener noreferrer"&gt;Repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First we're gonna clean up our App.tsx component&lt;br&gt;
&lt;code&gt;./src/App.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function App() {
  return (
    &amp;lt;div&amp;gt;
      Hello world!!!
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lets create a ButtonComponent.tsx file in the following path:&lt;br&gt;
&lt;code&gt;./src/components/Button/index.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Button } from "@material-ui/core";

export const ButtonComponent = ({
  children,
  variant,
  color,
  handleClick,
}) =&amp;gt; {
  return (
    &amp;lt;Button variant={variant} color={color} onClick={handleClick}&amp;gt;
      {children}
    &amp;lt;/Button&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So good, so fine! but, if you remember we're using TypeScript right? &lt;/p&gt;

&lt;p&gt;So, let's create an interface for the props in the following path:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/types/Interfaces.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ReactChildren } from "react";

export interface IButtonProps {
    children: JSX.Element | ReactChildren | string;
    variant: 'contained' | 'outlined' | 'text' | undefined;
    color: 'primary' | 'secondary' | 'default' | undefined;
    handleClick: () =&amp;gt; void;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and... we're gonna return to our previous component and add the new created interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Button } from "@material-ui/core";
import { IButtonProps } from "../../types/Interfaces";

export const ButtonComponent = ({
  children,
  variant,
  color,
  handleClick,
}: IButtonProps) =&amp;gt; {
  return (
    &amp;lt;Button variant={variant} color={color} onClick={handleClick}&amp;gt;
      {children}
    &amp;lt;/Button&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to return to our App.tsx component and add our new ButtonComponent created&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/App.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ButtonComponent } from "./components/Button";

function App() {
  return (
    &amp;lt;div&amp;gt;
        &amp;lt;ButtonComponent
          variant="contained"
          color="primary"
          handleClick={handleClick}
        &amp;gt;
          Open Modal [F1] || [F2] || [F3]
        &amp;lt;/ButtonComponent&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're going to create a custom hook to handle the Keypress events logic and made it reusable across our components.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/hooks/useKeyEvents.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from "react";

export const useKeyEvents = (key: string, callback: () =&amp;gt; void): boolean =&amp;gt; {
  const [keyPressed, setKeyPressed] = useState&amp;lt;boolean&amp;gt;(false);

  useEffect(() =&amp;gt; {
    const handleKeyDown = (e: KeyboardEvent) =&amp;gt; {
      if (e.key === key) {
        e.preventDefault();
        setKeyPressed(true);
        callback();
      }
    };

    window.addEventListener("keydown", handleKeyDown);

    return () =&amp;gt; {
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, [key, callback]);

  return keyPressed;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're gonna use React Context API to handle our global state so we need to create our Context:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/context/keyeventContext.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createContext, useContext } from "react";

const initialState = {
  isOpen: false,
  setIsOpen: () =&amp;gt; {},
  handleClick: () =&amp;gt; {}
};
const KeyEventContext = createContext(initialState);

export const useKeyEventContext = () =&amp;gt; useContext(KeyEventContext);

export default KeyEventContext;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we're gonna return to our Interfaces.tsx file and add a new Interface for our Context&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/types/Interfaces.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Our previous Interface

export interface IEventContext {
    isOpen: boolean;
    setIsOpen: React.Dispatch&amp;lt;React.SetStateAction&amp;lt;boolean&amp;gt;&amp;gt;
    handleClick: () =&amp;gt; void;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and now, we import our interface in our keyeventContext.tsx file and added to our createContext function as generic type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createContext, useContext } from "react";
import { IEventContext } from "../types/Interfaces";

const initialState = {
  isOpen: false,
  setIsOpen: () =&amp;gt; {},
  handleClick: () =&amp;gt; {}
};
const KeyEventContext = createContext&amp;lt;IEventContext&amp;gt;(initialState);

export const useKeyEventContext = () =&amp;gt; useContext(KeyEventContext);

export default KeyEventContext;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we need to create our Provider component to wrap our App component: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/context/keyeventState.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from "react";
import KeyEventContext from "./keyeventContext";
import { useKeyEvents } from "../hooks/useKeyEvents";

export const KeyEventState: React.FC = ({ children }) =&amp;gt; {
  const [isOpen, setIsOpen] = useState&amp;lt;boolean&amp;gt;(false);

  const handleClick = () =&amp;gt; {
    console.log('Our &amp;lt;ButtonComponent /&amp;gt; was clicked');
  };

  useKeyEvents("F1", () =&amp;gt; {
    console.log('F1 pressed');
  });

  useKeyEvents("F2", () =&amp;gt; {
    console.log('F2 pressed');
  });

  useKeyEvents("F3", () =&amp;gt; {
    console.log('F3 pressed');
  });
  return (
    &amp;lt;KeyEventContext.Provider value={{ isOpen, setIsOpen, handleClick }}&amp;gt;
      {children}
    &amp;lt;/KeyEventContext.Provider&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to import our useKeyEventContext created in our keyeventContext.tsx in our App.tsx file component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ButtonComponent } from "./components/Button";
import { useKeyEventContext } from "./context/keyeventContext";

function App() {
  const { isOpen, setIsOpen, handleClick } = useKeyEventContext();

  return (
    &amp;lt;div&amp;gt;
        &amp;lt;ButtonComponent
          variant="contained"
          color="primary"
          handleClick={handleClick}
        &amp;gt;
          Open Modal [F1] || [F2] || [F3]
        &amp;lt;/ButtonComponent&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We import our KeyEventState and wrap our App Component in the main.tsx file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import { KeyEventState } from './context/keyeventState'

ReactDOM.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;KeyEventState&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/KeyEventState&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
  document.getElementById('root')
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we test our App until now to see what we're achieving.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthgkwnilcg0cpeeby52r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthgkwnilcg0cpeeby52r.png" alt="pressed button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzn8nrzpam42d8utevjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzn8nrzpam42d8utevjl.png" alt="F1 pressed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfwvwuwo6flea9z0fvwa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfwvwuwo6flea9z0fvwa.png" alt="F2 pressed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6udi37afc78osft830z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6udi37afc78osft830z.png" alt="F3 pressed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wow, it's working! but we need yet to create our Modal component using React portals so... &lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/components/Portal/index.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useLayoutEffect } from "react";
import { createPortal } from "react-dom";

type State = HTMLElement | null;

function createWrapperAndAppendToBody(wrapperId: string) {
  const wrapperElement = document.createElement("div");
  wrapperElement.setAttribute("id", wrapperId);
  document.body.appendChild(wrapperElement);
  return wrapperElement;
}


function Portal({ children, id = "modal-id" }) {
  const [wrapperElement, setWrapperElement] = useState&amp;lt;State&amp;gt;(null);

  useLayoutEffect(() =&amp;gt; {
    let element = document.getElementById(id) as HTMLElement;
    let systemCreated = false;

    if (!element) {
      systemCreated = true;
      element = createWrapperAndAppendToBody(id);
    }
    setWrapperElement(element);

    return () =&amp;gt; {
      if (systemCreated &amp;amp;&amp;amp; element.parentNode) {
        element.parentNode.removeChild(element);
      }
    };
  }, [id]);

  if (wrapperElement === null) return null;

  return createPortal(children, wrapperElement as HTMLElement);
}

export default Portal;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create another Interface named IPortalProps in our Interfaces.tsx file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// Our previous interfaces ...

export interface IPortalProps {
    id: string;
    children: JSX.Element | ReactChildren | string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we import and use our new created interface in our Portal component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useLayoutEffect } from "react";
import { createPortal } from "react-dom";
import { IPortalProps } from "../../types/Interfaces";

type State = HTMLElement | null;

// Our createWrapperAndAppendToBody function

function Portal({ children, id = "modal-id" }: IPortalProps) {
  const [wrapperElement, setWrapperElement] = useState&amp;lt;State&amp;gt;(null);

  // Our useLayourEffect logic &amp;amp; other stuff

  return createPortal(children, wrapperElement as HTMLElement);
}

export default Portal;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create a Modal component&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/components/Modal/index.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useEffect, useRef } from "react";
import { CSSTransition } from "react-transition-group";
import { Paper, Box } from "@material-ui/core";
import { ButtonComponent } from "../Button";
import Portal from "../Portal";

function Modal({ children, isOpen, handleClose }) {
  const nodeRef = useRef(null);

  useEffect(() =&amp;gt; {
    const closeOnEscapeKey = (e: KeyboardEvent) =&amp;gt;
      e.key === "Escape" ? handleClose() : null;
    document.body.addEventListener("keydown", closeOnEscapeKey);
    return () =&amp;gt; {
      document.body.removeEventListener("keydown", closeOnEscapeKey);
    };
  }, [handleClose]);

  return (
    &amp;lt;Portal id="modalId"&amp;gt;
      &amp;lt;CSSTransition
        in={isOpen}
        timeout={{ enter: 0, exit: 300 }}
        unmountOnExit
        nodeRef={nodeRef}
        classNames="modal"
      &amp;gt;
        &amp;lt;div className="modal" ref={nodeRef}&amp;gt;
          &amp;lt;ButtonComponent
            variant="contained"
            color="secondary"
            handleClick={handleClose}
          &amp;gt;
            Close
          &amp;lt;/ButtonComponent&amp;gt;
          &amp;lt;Box
            sx={{
              display: "flex",
              flexWrap: "wrap",
              "&amp;amp; &amp;gt; :not(style)": {
                m: 1,
                width: "20rem",
                height: "20rem",
              },
            }}
          &amp;gt;
            &amp;lt;Paper elevation={3}&amp;gt;
              &amp;lt;div
                style={{
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "center",
                  marginTop: '4rem',
                }}
              &amp;gt;
                {children}
              &amp;lt;/div&amp;gt;
            &amp;lt;/Paper&amp;gt;
          &amp;lt;/Box&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/CSSTransition&amp;gt;
    &amp;lt;/Portal&amp;gt;
  );
}
export default Modal;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we create another Interface for Props in our Modal component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// All interfaces previously created so far

export interface IModalProps {
    isOpen: boolean;
    children: JSX.Element | ReactChildren | string;
    handleClose: () =&amp;gt; void;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, we import our new interface in our Modal component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// All others previous import 
import { IModalProps } from "../../types/Interfaces";
function Modal({ children, isOpen, handleClose }: IModalProps) {

// All logic stuff for the Modal component

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we create a new css file to add styles for our Modal&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/components/Modal/modalStyle.css&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.modal {
    position: fixed;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.3);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    transition: all 0.3s ease-in-out;
    overflow: hidden;
    z-index: 999;
    padding: 40px 20px 20px;
    opacity: 0;
    pointer-events: none;
    transform: scale(0.4);
  }


  .modal-enter-done {
    opacity: 1;
    pointer-events: auto;
    transform: scale(1);
  }
  .modal-exit {
    opacity: 0;
    transform: scale(0.4);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we install &lt;code&gt;react-transition-group&lt;/code&gt; package into our project to add some transition animations on our Modal component giving it a very good looking effect and we import our new created modalStyle.css file to our Modal file&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/components/Modal/index.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//All other imports 
import "./modalStyle.css";

function Modal({ children, isOpen, handleClose }: IModalProps) {
// All logic of our Modal component
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Until now our ButtonComponent is placed at the left upper corner, so we're going to create a new LayOut Component to Wrap our  to position it to the center.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/components/Layout/index.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Box from "@material-ui/core/Box";

export const LayOut: React.FC = ({ children }) =&amp;gt; {
  return (
    &amp;lt;div style={{ width: "100%" }}&amp;gt;
      &amp;lt;Box
        display="flex"
        justifyContent="center"
        m={2}
        p={2}
        bgcolor="background.paper"
      &amp;gt;
        {children}
      &amp;lt;/Box&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, now we are going to finish our App importing our Layout Component and our new Modal to the App Component.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/App.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ButtonComponent } from "./components/Button";
import { LayOut } from "./components/Layout";
import Modal from "./components/Modal";
import { useKeyEventContext } from "./context/keyeventContext";

function App() {
  const { isOpen, setIsOpen, handleClick } = useKeyEventContext();

  const handleClose = () =&amp;gt; setIsOpen(false)

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;LayOut&amp;gt;
        &amp;lt;ButtonComponent
          variant="contained"
          color="primary"
          handleClick={handleClick}
        &amp;gt;
          Open Modal [F1] || [F2] || [F3]
        &amp;lt;/ButtonComponent&amp;gt;
        &amp;lt;Modal isOpen={isOpen} handleClose={handleClose}&amp;gt;
          Hi there, i'm a modal
        &amp;lt;/Modal&amp;gt;
      &amp;lt;/LayOut&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are going to think, yay! we did it so far! we're done! but no, we need to add a little change on our keyeventState.tsx file to complete the functionality desired.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/context/keyeventState.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from "react";
import KeyEventContext from "./keyeventContext";
import { useKeyEvents } from "../hooks/useKeyEvents";

export const KeyEventState: React.FC = ({ children }) =&amp;gt; {
  const [isOpen, setIsOpen] = useState&amp;lt;boolean&amp;gt;(false);

  const handleClick = () =&amp;gt; {
    setIsOpen(true);
  };

  useKeyEvents("F1", () =&amp;gt; {
    setIsOpen(true);
  });

  useKeyEvents("F2", () =&amp;gt; {
    setIsOpen(true);
  });

  useKeyEvents("F3", () =&amp;gt; {
    setIsOpen(true);
  });
  return (
    &amp;lt;KeyEventContext.Provider value={{ isOpen, setIsOpen, handleClick }}&amp;gt;
      {children}
    &amp;lt;/KeyEventContext.Provider&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the magic happens when you press your F1 to F3 keys and ESC key to close our Modal.&lt;/p&gt;

&lt;p&gt;We did it so far in this article until now, but remember only practice makes a master.&lt;/p&gt;

&lt;p&gt;Remember to keep improving and investigating new things to add to your projects and get better and better.&lt;/p&gt;

&lt;p&gt;Tell me your thoughts about this post in the comments and see ya in another post!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>customhooks</category>
      <category>reacthooks</category>
    </item>
  </channel>
</rss>
