35
loading...
This website collects cookies to deliver better user experience
src/AppShell.jsx
import React, { useState } from 'react'
import { BrowserRouter, NavLink, Route, Switch } from 'react-router-dom'
import ScreenOne from './components/screen-one/ScreenOne'
import ScreenTwo from './components/screen-two/ScreenTwo'
import ScreenThree from './components/screen-three/ScreenThree'
import ModalOne from './components/common/modal-one/ModalOne'
import ModalTwo from './components/common/modal-two/ModalTwo'
import ModalThree from './components/common/modal-three/ModalThree'
import './app-shell.css'
const AppShell = () => {
const [modalOpen, setModal] = useState(false)
const openModal = event => {
event.preventDefault()
const { target: { dataset: { modal }}} = event
if (modal) setModal(modal)
}
const closeModal = () => {
setModal('')
}
return (
<BrowserRouter>
<div className="app--shell" onClick={openModal}>
{/* Application header and navigation */}
<header className="app--header">
<h1>React Modal Windows</h1>
<nav className="app--nav">
<NavLink to="/screen-one">Screen One</NavLink>
<NavLink to="/screen-two">Screen Two</NavLink>
<NavLink to="/screen-three">Screen Three</NavLink>
</nav>
</header>
{/* Application screens */}
<Switch>
<Route path="/screen-three">
<ScreenThree />
</Route>
<Route path="/screen-two">
<ScreenTwo />
</Route>
<Route path="/screen-one">
<ScreenOne />
</Route>
<Route exact path="/">
<ScreenOne />
</Route>
</Switch>
{/* Modals */}
<ModalOne
closeFn={closeModal}
open={modalOpen === 'modal-one'} />
<ModalTwo
closeFn={closeModal}
open={modalOpen === 'modal-two'} />
<ModalThree
closeFn={closeModal}
open={modalOpen === 'modal-three'} />
{/* Application footer */}
<footer className="app--footer">
<p className="copyright">© 2021 Some Company</p>
</footer>
</div>
</BrowserRouter>
)
}
export default AppShell
ScreenSwitchboard.jsx
and ModalManager.jsx
so our AppShell.jsx
component might look a little cleaner similar toimport React, { useState } from 'react'
import { BrowserRouter } from 'react-router-dom'
import AppHeader from './AppHeader'
import AppFooter from './AppFooter'
import ScreenSwitchboard from './ScreenSwitchboard'
import ModalManager from './ModalManager'
import './app-shell.css'
const AppShell = () => {
const [modalOpen, setModal] = useState(false)
const openModal = event => {
event.preventDefault()
const { target: { dataset: { modal }}} = event
if (modal) setModal(modal)
}
const closeModal = () => {
setModal('')
}
return (
<BrowserRouter>
<div className="app--shell" onClick={openModal}>
<AppHeader />
<ScreenSwitchboard />
<ModalManager closeFn={closeModal} modal={modalOpen} />
<AppFooter />
</div>
</BrowserRouter>
)
}
export default AppShell
#app--shell
element. Our event handler openModal
that would trigger opening a specific modal looks for data-modal
attribute which we could set on some elements (buttons, links, etc.) in our application.import React from 'react'
const ScreenOne = ({}) => {
return (
<main className="app--screen screen--one">
<h2>Screen One</h2>
<div style={{ display: 'flex', columnGap: '1rem' }}>
<button type="button" data-modal="modal-one">Open Modal One</button>
<button type="button" data-modal="modal-two">Open Modal Two</button>
<button type="button" data-modal="modal-three">Open Modal Three</button>
</div>
</main>
)
}
export default ScreenOne
data-modal
attribute and event bubbling to handle opening a specific modal.<ModalManager />
component expects two props: state value as modal
prop describing which modal should be open and closeFn
prop which effectively directs the application to close any open modal.<ModalManager />
component:import React from 'react'
import ModalOne from './components/common/modal-one/ModalOne'
import ModalTwo from './components/common/modal-two/ModalTwo'
import ModalThree from './components/common/modal-three/ModalThree'
const ModalManager = ({
closeFn = () => null,
modal = ''
}) => (
<>
<ModalOne
closeFn={closeFn}
open={modal === 'modal-one'} />
<ModalTwo
closeFn={closeFn}
open={modal === 'modal-two'} />
<ModalThree
closeFn={closeFn}
open={modal === 'modal-three'} />
</>
)
export default ModalManager
src/components/common/modal/Modal.jsx
component:import React, { useEffect } from 'react'
import ReactDOM from 'react-dom'
const modalRootEl = document.getElementById('modal-root')
const Modal = ({
children,
open = false
}) => {
if (!open) return null
return ReactDOM.createPortal(children, modalRootEl)
}
export default Modal
#modal-root
element will be available somewhere in our document, preferably as a sibling #app-root
element where our application is mounted.<body />
in index.html
could look like this:<body>
<div id="app-root"></div>
<div id="modal-root"></div>
</body>
import React from 'react';
import Modal from '../modal/Modal';
const ModalOne = ({ closeFn = () => null, open = false }) => {
return (
<Modal open={open}>
<div className="modal--mask">
<div className="modal-window">
<header className="modal--header">
<h1>Modal One</h1>
</header>
<div className="modal--body">
<p>Modal One content will be rendered here.</p>
</div>
<footer className="modal--footer">
<button type="button" onClick={closeFn}>
Close
</button>
</footer>
</div>
</div>
</Modal>
);
};
export default ModalOne;