Introduction
In this article, we'll walk through the process of implementing a modal component with React.
The above image shows the user interface (UI) of the project we would be working on. The UI displays a couple of profile cards and each profile card represents a person with their name and profile picture, while the modal component displays additional information about each selected profile, including their name, role, skills, and profile picture.
Let's get started!
Prerequisite
Before starting, ensure that Node.js and NPM are installed on your system. You can check if you have these installed by running the following commands in your terminal:
node -v
npm -v
If you do not have these packages installed on your computer, download and install Node.js from the official website.
Also, a basic knowledge of JavaScript and React is needed.
Setting your React project with Vite
Follow the process outlined in this blog post Setting your React project with Vite to create a new React project.
In the new React project, remove the pre-existing code and styles in the index.css
, App.jsx
, and App.css
files.
Step-by-step process on how to implement a modal component with React
STEP 1: Import packages and files
Inside the project directory, navigate to the App.jsx file and import the necessary package and file.
import { useState } from 'react';
import './App.css';
This imports the useState hook from the 'react' package, which allows you to use state in functional components. It also imports the 'App.css' file for styling.
Within the src
directory, create a components
folder and add the following files along with their corresponding CSS files: card.jsx
, modal.jsx
, card.css
, and modal.css
.
src/
│ components/
│ Card/
Card.jsx
Card.css
│ Modal/
Modal.jsx
Modal.css
│ App.css/
│ App.jsx/
│ index.css/
│ main.jsx/
STEP 2: Create the App component
In this next step, create a functional component named App
and initialize a state variable using the useState
hook and import the App.css
file, which contains CSS styles for the App
component. We also import the Card
component from the ./components/card/card
file.
import { useState } from 'react';
import './App.css';
import Card from './components/card/card';
const App = () => {
const [profiles, updateProfiles] = useState([
{ id: 1, name: "Sophia Anderson", role: "Frontend Engineer", skills: ["HTML", "CSS", "JavaScript", "React", "Next.js"], profilePic: "https://rb.gy/9jh39"},
{ id: 2, name: "Isabella Sullivan", role: "Senior Java Developer", skills: ["Java", "Spring Boot", "Spring Framework", "Maven"], profilePic: "https://rb.gy/gs5lt"},
{ id: 3, name: "Ava Reynolds", role: "Backend Developer", skills: ["Node.js", "Express", "MongoDB", "Nest.js"], profilePic: "https://rb.gy/rs32e"},
{ id: 4, name: "Olivia Thompson", role: "Blockchain Developer", skills: ["Web3", "JavaScript", "Solidity", "Rust", "Smart contracts"], profilePic: "https://rb.gy/xbjed"},
])
return (
<div className='App'>
<div className='profile-card'>
{profiles.map(profile =>{
return(< Card
key={profile.id}
id={profile.id}
name={profile.name}
skills={profile.skills}
role={profile.role}
profilePic={profile.profilePic}
/>)
})}
</div>
</div>
);
};
Code explanation
We declare a state variable called profiles
and updateProfiles
to update the state. The profiles
state variable contains an array of user/profile objects with various properties such as id
, name
, role
, skills
, and profilePic
.
We declare a return statement that returns the JSX code that will be rendered to the DOM.
Next, we use the .map()
function on the profiles
array which iterates over each profile
object in the array and returns a <Card/>
component for each profile. The properties of the profile object (such as id, name, skills, role, and profilePic) are passed as props to the <Card/>
component.
It is important to pass a key prop
key={profile.id}
to the card component within theprofiles.map
function. This is because the key prop value will be used as a unique identifier for each profile in theprofiles
array.In React, the key prop is not accessible within the component but it is primarily used by React to update the list and maintain the state and order of the component.
STEP 3: Style the App component
Add the CSS styles below to your App.css
file to style the App component.
.App {
text-align: center;
margin: 10rem 3rem;
}
.profile-card{
display: flex;
flex-direction: row;
justify-content: space-around;
margin-top: 4rem;
}
STEP 4: Create the card component
In this step, we create a functional component named Card
and initialize a state variable using the useState
hook and import the Card.css
file, which contains CSS styles for the Card component.
import './Card.css'
import Modal from '../Modal/Modal';
import { useState } from 'react';
const Card = ({id, name, profilePic, skills, role}) => {
const [showModal, setShowModal] = useState(false)
const handleClose = () => {setShowModal(false)}
return (
<>
<div className="card">
<div className="number">{id}</div>
<div>
<img className="profile-pic" src={profilePic} alt="profile picture" />
</div>
<div className="descr">
<p className="name">{name}</p>
<button className="learn-more" onClick={() =>setShowModal(true)}>Click to learn more</button>
</div>
</div>
{showModal && <Modal name={name} role={role} skills={skills} profilePic={profilePic} handleClose={handleClose}/>}
</>
);
};
export default Card;
Code explanation
Firstly, we declare a new component called card
using the arrow function expression. In the previous step, the card component received an object of props as an argument. We use destructuring to extract some properties (id, name, profilePic, skills, and role) from the props object.
const [showModal, setShowModal] = useState(false)
const handleClose = () => {setShowModal(false)}
In the card component, we declare a state variable called showModal
and setShowModal
to update the state. The initial value of showModal
is set to false
to hide the modal. We declare a function named handleClose
that sets the showModal
state to false
, which closes the modal when it is called.
We declare the return statement and then we pass each of the prop values into the JSX element so each profile card can be rendered to the DOM.
<button className="learn-more" onClick={() => setShowModal(true)}>Click to learn more</button>
Next, We pass an onClick
event to the learn more
button in the card component. When the button is clicked, it triggers an onClick
event that calls the setShowModal
function with true
as the argument. This updates the showModal
state and shows the modal.
{showModal && <Modal name={name} role={role} skills={skills} profilePic={profilePic} handleClose={handleClose}/>
Finally, we import the modal component from the modal directory and render the modal component in the card component. The modal component is only rendered if showModal
is true, and we pass in various props such as name
, role
, skills
, profilePic
, and the handleClose
function to the modal component. When the modal is rendered, the handleClose
function is passed as a prop to handle its close action.
STEP 5: Style the card component
Add the CSS styles below to your Card.css
file to style the card component.
.card {
border: 1px solid rgba(0, 0, 0, 0.175);
border-radius: 10px;
}
.number{
text-align: right;
font-size: 1.5rem;
font-weight: 700;
padding: 0.8rem;
}
.name{
font-size: 1.8rem;
font-weight: 600;
}
.profile-pic{
width: 100%;
height: 300px;
}
.descr{
margin-bottom: 1.5rem;
}
.learn-more{
padding: 0.8rem;
outline: none;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 1.5rem;
}
.learn-more:hover{
background-color: #6a6d6d;
color: #ffff;
}
@media screen and (max-width: 1400px) {
.profile-card{
display: flex;
flex-direction: column;
margin-top: 1rem;
}
.card{
margin-top: 3rem;
}
}
STEP 6: Create the modal component
In this next step, we create a functional component named Modal
and import the Modal.css
file, which contains CSS styles for the Modal component.
import './Modal.css'
const Modal = ({name, profilePic, handleClose, skills, role}) => {
return (
<div className="modal-backdrop">
<div className="modal">
<img className="modal-img" src={profilePic} alt="profile pic" />
<div className="modal-body">
<div className='modal-name'>{name}</div>
<div className='modal-role'>{role}</div>
<div className="skills">
<ul>
{skills.map(skill => <li key={skill}>{skill}</li>)}
</ul>
</div>
</div>
<button className="close-btn" onClick={()=> handleClose()}> Close</button>
</div>
</div>
);
};
export default Modal;
Code explanation
We declare a new component called ‘modal’ using the arrow function expression. In the previous step, the card component received an object of props as an argument. Then, we destructure the specific props such as name
, profilePic
, handleClose
, skills
, and role
from the props object.
We declare the return statement and then we pass each of the prop values into the JSX elements to be rendered.
{skills.map(skill => <li key={skill}>{skill}</li>)}
The skills
prop value consists of a list of skills
arrays. So we use the map function to iterate over the skills
array. It returns a new array of list items <li>
with each skill as its content. The key attribute is set to the skill for proper identification of list items.
<button className="close-btn" onClick={()=> handleClose()}>Close</button>
Lastly, we pass an onClick
event to the close button in the modal component. When the button is clicked, it triggers the onClick
event that calls the handleClose
function, which was passed as a prop to handle the closing action of the modal.
STEP 7: Style the modal component
Add the CSS styles below to your Modal.css
file to style the modal component.
.modal-backdrop {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
}
.modal {
max-width: 480px;
height: 400px;
margin: 150px auto;
background-color: #ffff;
border-radius: 10px;
padding: 0;
}
.modal-img{
border-radius: 50%;
height: 100px;
width: 100px;
margin: 4rem 0 2rem;
}
.modal-name {
font-size: 2rem;
font-weight: 600;
}
.modal-role{
font-size: 1.5rem;
font-weight: 600;
margin-top: 1.5rem;
font-style: italic;
}
.skills ul {
display: flex;
padding: 0;
justify-content: center;
margin-top: 0;
}
.skills li {
list-style-type: none;
margin-right: 10px;
color: black;
background-color: #ebebf2;
padding: 0.5rem 1rem;
margin: 2rem 0.5rem;
font-size: 1.3rem;
border-radius: 5px;
font-weight: 600;
}
.close-btn{
background-color: #ebebf2;
border-radius: 3px;
cursor: pointer;
font-size: 1.5rem;
padding: 1rem 2rem;
margin-top: 2rem;
outline: none;
border: none;
font-weight: 500;
text-transform: uppercase;
}
.close-btn:hover,
.close-btn:focus{
background-color: #9393B2;
color: #ffff;
}
@media screen and (max-width: 480px) {
.skills li {
padding: 0.5rem 0.8rem;
margin: 2rem 0.4rem;
font-size: 1rem;
}
}
We have successfully implemented a modal component with React and you can find the complete code for this tutorial on GitHub and the live link.