Reactでモーダルを実装してみた
これは ZOZO Advent Calendar 2022 カレンダー Vol.4 の 4 日目の記事です。
表題の通り、Reactでモーダルを実装するということで、CodeSandboxを使って開発していきます。
今回は初心者向けに基本的な機能のみ実装しています。🙇♂️
参考にするのはChakra UIです。
完成したコードだけみたい人はこちらを見て下さい!
それでは早速CodeSandboxでテンプレートを用意しましょう!
テンプレート作成
手順
1.左上のCreateをクリック
2.Reactをクリック
3.Hello CodeSandboxが出たら準備完了
モーダル作成
Reactを動かせる環境が用意できたということで次はモーダルの実装に入っていきましょう!
1.モーダルに必要なUIの作成
UIはChakra UIを参考にします。
手順
1.Componetnts/Modal.jsxファイルを作成
2.下記コードをコピペ
export const Modal = () => {
return (
<div className="container">
<section className="containerInner">
<h2 className="header">Modal title</h2>
<button
type="button"
aria-label="閉じる"
className="iconClose"
>
×
</button>
<p className="contents">
Sit nulla est ex deserunt exercitation anim occaecat. Nostrud ullamco
deserunt aute id consequat veniam incididunt duis in sint irure nisi.
Mollit officia cillum Lorem ullamco minim nostrud elit officia tempor
esse quis. Sunt ad dolore quis aute consequat. Magna exercitation
reprehenderit magna aute tempor cupidatat consequat elit dolor
adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis.
Velit duis sit officia eiusmod Lorem aliqua enim laboris do dolor
eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod
pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
</p>
<div className="buttonContainer">
<button
type="button"
className="button closeButton"
>
close
</button>
<button type="button" className="button nextButton">
Secondary Action
</button>
</div>
</section>
</div>
);
};
- <div className="App">
- <h1>Hello CodeSandbox</h1>
- <h2>Start editing to see some magic happen!</h2>
- </div>
+ <div className="App">
+ <button type="button" className="button openButton">
+ Open Modal
+ </button>
+ <Modal/>
+ </div>
body,
h2,
p {
padding: 0;
margin: 0;
}
* {
box-sizing: border-box;
}
.header {
font-size: 20px;
padding: 16px 24px;
}
.App {
min-height: 200vh;
background-color: greenyellow;
}
.buttonContainer {
display: flex;
justify-content: flex-end;
padding: 16px 24px;
}
.contents {
padding: 8px 24px;
}
.containerInner {
position: relative;
display: flex;
flex-direction: column;
background-color: #fff;
width: 462px;
border: 1px solid black;
border-radius: 10px;
}
.button {
padding: 8px 16px;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
border: none;
}
.openButton {
background-color: #edf2f7;
}
.openButton:hover {
background-color: #e2e8f0;
}
.closeButton {
background-color: #3182ce;
color: #fff;
}
.closeButton:hover {
background-color: #2b6cb0;
}
.nextButton {
background-color: transparent;
margin-left: 4px;
}
.nextButton:hover {
background-color: #e2e8f0;
}
.iconClose {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 10px;
right: 10px;
background-color: transparent;
border: none;
font-size: 30px;
height: 30px;
width: 30px;
border-radius: 10px;
cursor: pointer;
}
.iconClose:hover {
background-color: #e2e8f0;
}
このようになると思います。
2.モーダルの機能を追加
手順
開閉機能の追加
1.Componetnts/useModal.jsxファイルを作成
2.カスタムフックを作成
import { useCallback, useState } from "react";
export const useModal = () => {
const [isOpen, setIsOpen] = useState(false);
const onOpen = useCallback(() => {
setIsOpen(true);
}, [setIsOpen]);
const onClose = useCallback(() => {
setIsOpen(false);
}, [setIsOpen]);
return { isOpen, onOpen, onClose };
};
3.カスタムフックを使って開閉機能を実装
export default function App() {
+ const { isOpen, onClose, onOpen } = useModal();
return (
<div className="App">
+ <button onClick={onOpen} type="button" className="button openButton">
Open Modal
</button>
+ {isOpen && <Modal onClose={onClose} />}
</div>
);
}
+ export const Modal = ({ onClose }) => {
return (
<div className="container">
<section className="containerInner">
<h2 className="header">Modal title</h2>
<button
+ onClick={onClose}
type="button"
aria-label="閉じる"
className="iconClose"
>
×
</button>
<p className="contents">
Sit nulla est ex deserunt exercitation anim occaecat. Nostrud ullamco
deserunt aute id consequat veniam incididunt duis in sint irure nisi.
Mollit officia cillum Lorem ullamco minim nostrud elit officia tempor
esse quis. Sunt ad dolore quis aute consequat. Magna exercitation
reprehenderit magna aute tempor cupidatat consequat elit dolor
adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis.
Velit duis sit officia eiusmod Lorem aliqua enim laboris do dolor
eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod
pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
</p>
<div className="buttonContainer">
<button
+ onClick={onClose}
type="button"
className="button closeButton"
>
close
</button>
<button type="button" className="button nextButton">
Secondary Action
</button>
</div>
</section>
</div>
);
};
スクロールの制御機能を追加
1.背景の追加
export const Modal = ({ onClose }) => {
return (
<div className="container">
+ <div className="overlay" onClick={onClose} />
<section className="containerInner">
<h2 className="header">Modal title</h2>
<button
onClick={onClose}
type="button"
aria-label="閉じる"
className="iconClose"
>
×
</button>
.overlay {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.4);
}
このようになります!
今のままだとモーダルが開いた状態でもスクロールできてしまうので、
これからスクロールを制御しましょう。
2.モーダルが開いている時に下のコンテンツが動かないようにする
今回はoverscroll-behaviorプロパティを使ってスクロールを制御します。
ついでにモーダルを中央揃えにしましょう。
.overlay {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.4);
+ overscroll-behavior: contain;
+ overflow-y: scroll;
}
.container {
position: fixed;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
min-height: 100%;
top: 0;
left: 0;
overscroll-behavior: contain;
overflow-y: scroll;
}
次にコンテンツ部分に長い文章が入った場合にコンテンツの中身をスクロールできるようにしましょう!
まずモーダルのコンテンツ部分に長い文章を入れましょう。
<p className="contents">
Sit nulla est ex deserunt exercitation anim occaecat. Nostrud ullamco
deserunt aute id consequat veniam incididunt duis in sint irure nisi.
Mollit officia cillum Lorem ullamco minim nostrud elit officia tempor
esse quis. Sunt ad dolore quis aute consequat. Magna exercitation
reprehenderit magna aute tempor cupidatat consequat elit dolor
adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis.
Velit duis sit officia eiusmod Lorem aliqua enim laboris do dolor
eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod
pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
Est velit labore esse esse cupidatat. Velit id elit consequat minim.
Mollit enim excepteur ea laboris adipisicing aliqua proident occaecat
do do adipisicing adipisicing ut fugiat. Consequat pariatur ullamco
aute sunt esse. Irure excepteur eu non eiusmod. Commodo commodo et ad
ipsum elit esse pariatur sit adipisicing sunt excepteur enim.
Incididunt duis commodo mollit esse veniam non exercitation dolore
occaecat ea nostrud laboris. Adipisicing occaecat fugiat fugiat irure
fugiat in magna non consectetur proident fugiat. Commodo magna et
aliqua elit sint cupidatat. Sint aute ullamco enim cillum anim ex. Est
eiusmod commodo occaecat consequat laboris est do duis. Enim
incididunt non culpa velit quis aute in elit magna ullamco in
consequat ex proident. Dolore incididunt mollit fugiat pariatur
cupidatat ipsum laborum cillum. Commodo consequat velit cupidatat duis
ex nisi non aliquip ad ea pariatur do culpa. Eiusmod proident
adipisicing tempor tempor qui pariatur voluptate dolor do ea commodo.
Veniam voluptate cupidatat ex nisi do ullamco in quis elit. Cillum
proident veniam cupidatat pariatur laborum tempor cupidatat anim
eiusmod id nostrud pariatur tempor reprehenderit. Do esse ullamco
laboris sunt proident est ea exercitation cupidatat. Do Lorem eiusmod
aliqua culpa ullamco consectetur veniam voluptate cillum. Dolor
consequat cillum tempor laboris mollit laborum reprehenderit
reprehenderit veniam aliqua deserunt cupidatat consequat id. Est id
tempor excepteur enim labore sint aliquip consequat duis minim tempor
proident. Dolor incididunt aliquip minim elit ea. Exercitation non
officia eu id. Ipsum ipsum consequat incididunt do aliquip pariatur
nostrud. Qui ut sint culpa labore Lorem. Magna deserunt aliquip aute
duis consectetur magna amet anim. Magna fugiat est nostrud veniam.
Officia duis ea sunt aliqua. Ipsum minim officia aute anim minim aute
aliquip aute non in non. Ipsum aliquip proident ut dolore eiusmod ad
fugiat fugiat ut ex. Ea velit Lorem ut et commodo nulla voluptate
veniam ea et aliqua esse id. Pariatur dolor et adipisicing ea mollit.
Ipsum non irure proident ipsum dolore aliquip adipisicing laborum
irure dolor nostrud occaecat exercitation. Culpa qui reprehenderit
nostrud aliqua reprehenderit et ullamco proident nisi commodo non ut.
Ipsum quis irure nisi sint do qui velit nisi. Sunt voluptate eu
reprehenderit tempor consequat eiusmod Lorem irure velit duis Lorem
laboris ipsum cupidatat. Pariatur excepteur tempor veniam cillum et
nulla ipsum veniam ad ipsum ad aute. Est officia duis pariatur ad
eiusmod id voluptate. Duis est est do dolore magna proident labore do
irure. Irure aliquip cillum est esse mollit laborum esse anim sint ut
laboris ut proident culpa. Exercitation duis eu officia commodo.
Proident commodo esse occaecat velit enim non dolor ad nostrud.
Adipisicing enim est cupidatat culpa pariatur aliqua id tempor ipsum.
Ad nulla enim dolore ullamco occaecat mollit non veniam voluptate
labore. Culpa aute sit exercitation ad anim ad duis ut consequat id
irure. Ullamco id adipisicing sint proident anim eu eiusmod. Eu nisi
magna elit cupidatat nostrud duis anim proident enim nulla. Eu eu
veniam aute id aute. Tempor dolore dolor aute anim labore deserunt
anim ea est est. Id est amet minim est dolor et eu excepteur. Officia
sunt deserunt et proident ut esse aliqua ullamco nulla minim anim
adipisicing amet sit. Commodo ea Lorem excepteur dolor quis mollit
mollit veniam cillum minim quis ut ex. Est pariatur laborum
consectetur sit ut anim voluptate est reprehenderit tempor. Pariatur
aliquip culpa esse ipsum aute reprehenderit id commodo ea duis fugiat
voluptate nostrud excepteur. Cupidatat nostrud consequat id esse non
sunt ullamco eiusmod cillum laboris. Dolore consequat sit do cillum
mollit labore. Ut consequat dolore et ea elit. Do ea enim irure eu
velit aute. Irure esse aliqua ad velit culpa laboris sit nisi Lorem
dolore nostrud. Exercitation dolore minim anim do aliqua quis
reprehenderit do enim consectetur. Minim officia commodo amet sint
commodo ea officia. Lorem qui dolore occaecat elit irure aliquip sunt
tempor consectetur laborum adipisicing sunt. Laboris nisi culpa
cupidatat fugiat ullamco deserunt mollit incididunt ipsum. Commodo
nostrud qui esse mollit sunt velit est dolor esse irure pariatur velit
elit cillum. Amet eiusmod culpa aute mollit Lorem do laboris sit sunt
exercitation. Duis sunt ea ut consectetur cillum ullamco esse culpa.
Non Lorem non incididunt labore velit cillum nulla est consequat
nostrud ea anim.
</p>
.containerInner {
position: relative;
display: flex;
flex-direction: column;
background-color: #fff;
width: 462px;
border: 1px solid black;
border-radius: 10px;
+ height: 448px;
}
.{
.contents {
padding: 8px 24px;
+ overscroll-behavior: contain;
+ overflow-y: scroll;
}
}
以上で簡単なモーダルが完成しました!
最後に一手間加えましょう
createPortalを使ってモーダルを表示する
cratePortalを利用することで任意のDOM要素に子要素を追加できます。
今回はbody要素の最後にモーダルコンポーネントを追加して要素の上に常にモーダルを表示できるようにします。
1.Componetnts/reactPortal.jsxファイルを作成
2.createPortalの実装
import { createPortal } from "react-dom";
export const ModalPortal = ({ children }) => {
return createPortal(children, document.body);
};
return (
<div className="App">
<button onClick={onOpen} type="button" className="button openButton">
Open Modal
</button>
+ {isOpen && (
+ <ModalPortal>
+ <Modal onClose={onClose} />
+ </ModalPortal>
+ )}
</div>
);
Discussion