<div id="root">
<!-- This element's contents will be replaced with your component. -->
</div>
.App {
font-family: sans-serif;
text-align: center;
}
.modal-container {
z-index: 999;
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(255, 255, 255, 0.7);
font-size: 15px;
font-weight: bold;
color: #62626e;
}
.modal-content {
width: 80%;
height: 90%;
position: relative;
display: flex;
flex-direction: column;
border: 1px solid #d8dce3;
border-radius: 3px;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.5);
background-color: #f7f8fa;
}
.modal-header {
padding: 9px 10px;
padding-left: 20px;
height: 38px;
font-size: 15px;
position: relative;
}
.cross-btn {
padding: 0;
margin: 0;
background: transparent;
border: 0;
position: absolute;
right: 10px;
font-weight: bold;
cursor: pointer;
}
.modal-body {
flex-grow: 1;
border-top: solid 1px #d8dce3;
padding: 14px 29px 14px 19px;
}
.modal-footer {
border-top: solid 1px #d8dce3;
padding: 10px 20px;
display: flex;
justify-content: flex-end;
}
.close-btn {
font-weight: 600;
box-shadow: rgba(0, 0, 0, 0.35) 0px 2px 2px 0px;
background-color: rgb(77, 144, 255);
color: rgb(247, 248, 250);
height: 35px;
width: 117px;
font-size: 14px;
border-radius: 3px;
border-width: 1px;
border-style: solid;
border-color: rgb(43, 123, 255);
cursor: pointer;
}
function App() {
const [isModalVisible, setIsModalVisible] = React.useState(false);
return (
<div className="App">
<h1>Parent container</h1>
<h3>This is just a demo container</h3>
<button onClick={() => setIsModalVisible(true)}>open modal</button>
{isModalVisible && (
<Modal onModalClose={() => setIsModalVisible(false)}>
<Modal.Header>Header</Modal.Header>
<Modal.Body>Body</Modal.Body>
<Modal.Footer>
<Modal.Footer.CloseBtn>Close</Modal.Footer.CloseBtn>
</Modal.Footer>
</Modal>
)}
</div>
);
}
const modalContext = React.createContext();
function Modal({ children, onModalClose }) {
React.useEffect(() => {
function keyListener(e) {
const listener = keyListenersMap.get(e.keyCode);
return listener && listener(e);
}
document.addEventListener("keydown", keyListener);
return () => document.removeEventListener("keydown", keyListener);
});
const modalRef = React.createRef();
const handleTabKey = e => {
const focusableModalElements = modalRef.current.querySelectorAll(
'a[href], button, textarea, input[type="text"], input[type="radio"], input[type="checkbox"], select'
);
const firstElement = focusableModalElements[0];
const lastElement =
focusableModalElements[focusableModalElements.length - 1];
if (!e.shiftKey && document.activeElement !== firstElement) {
firstElement.focus();
return e.preventDefault();
}
if (e.shiftKey && document.activeElement !== lastElement) {
lastElement.focus();
e.preventDefault();
}
};
const keyListenersMap = new Map([[27, onModalClose], [9, handleTabKey]]);
return ReactDOM.createPortal(
<div className="modal-container" role="dialog" aria-modal="true">
<div className="modal-content" ref={modalRef}>
<modalContext.Provider value={{ onModalClose }}>
{children}
</modalContext.Provider>
</div>
</div>,
document.body
);
}
Modal.Header = function ModalHeader(props) {
const { onModalClose } = React.useContext(modalContext);
return (
<div className="modal-header">
{props.children}
<button className="cross-btn" title="close modal" onClick={onModalClose}>
✕
</button>
</div>
);
};
Modal.Body = function ModalBody(props) {
return <div className="modal-body">{props.children}</div>;
};
Modal.Footer = function ModalFooter(props) {
return <div className="modal-footer">{props.children}</div>;
};
Modal.Footer.CloseBtn = function CloseBtn(props) {
const { onModalClose } = React.useContext(modalContext);
return (
<button
{props}
className="close-btn"
title="close modal"
onClick={onModalClose}
/>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
View Compiled
This Pen doesn't use any external CSS resources.