How to create a modal
Tags: html, css, javascript
Published: 2021-06-22 11:13:40

---
title: How to create a modal
published: true
description: You'll learn how to create a modal using HTML, CSS, and a bit of JavaScript
tags: html, css, javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l12opuf34na33digpgk6.jpg
series: My WebDev Notes
---

## __Introduction__

Modals are User Interface (UI) elements that aim to grab users' attention by displaying information that overlays the entire web page or (rarely) parts of it.

In this article, I'll explain in detail how to create a modal using HTML, CSS, and a bit of JavaScript. The content of the modal would be a login form. Albeit, you could put anything you want in the modal, the lesson here is to show you _how it's done_ therefore, you can easily implement yours or add to what you'll learn therein.

In the end, I'll list other techniques that do not involve the usage of JavaScript when creating a modal.

## __Our final result__

As an inspiration, here is the completed modal, with all its sections highlighted. I am doing this so that you can know the thinking that goes behind the HTML and thus the final design. 

![A modal with its sections highlighted](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twuevow17oqpmfqln3ox.png)

As a challenge, you can stop here, and see if you can implement this without reading the remainder of the article.

## The HTML

From the image in the previous section, it's evident you'll need the following in your HTML markup:

* A button to trigger the modal
* A container for the modal
* An HTML form
* An image
* A container for the "X" symbol

In software engineering terms, these are the requirements. Below is the HTML code (excluding the DOCTYPE declaration, meta tags, and the opening and closing `body` tag).

```html
<main>
    <h2>Modal Login form</h2>

	<button  id="openModal" class="button openModal">Open Modal</button>

	<div id="modal" class="modal">
		<form class="form modal__content animate" action="#">	
			<div class="form__row">
				<span id="closeModal" class="closeModal" title="Close Modal">&times;</span>
				<img src="profile.png" alt="Avatar" class="form__avatar" width="300px">
			</div>

			<div class="form__row">
                <label for="username" class="form__label">Username</label>
				<input
                       id="username"
                       type="text"
                       placeholder="Enter your username"
                       name="username"
                       required
                       class="form__input"
                  >
                
                <label for="password" class="form__label">Password</label>
                <input
                       id="password"
                       type="password"
                       placeholder="Enter your password"
                       name="password"
                       required
                       class="form__input"
                      >
                
                <button class="button" type="submit">Login</button>
            </div>
            
            <div class="form__row modal__footer">
                <button
                        type="button"
                        id="cancelModal"
                        class="button cancelModal">Cancel
                </button>
			   <span class="forgetpassword">
                   <a class="forgetpassword__link" href="#">Forget password?</a>
                </span>
            </div>
        </form>
    </div>
</main>
```

Moving forward, perform the following steps:

- Create a project folder and call it any name the suits you.
- Create an `index.html` file with the DOCTYPE and meta tags.
- Type the HTML code above between the opening and closing body tags.

> <b>Note</b>: There is an image file referenced in the HTML code, called `profile.png`. It is the avatar depicted in the image of the final result. You can get a similar image from [Pexels](https://pexels.com) or [Unsplash](https://unsplash.com).

Save your `index.html` file and launch it in your browser. The result at this stage is short of _pretty_, but you are on the right track.

![Basic HTML for a modal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/flkdv0sffb8bhoihhrck.png)

Our next step is to add CSS to the markup, which will add some beauty and usability to the form.

## The CSS

The first thing you'll do is to beautify the buttons because as things stand, they are not looking good. Less I forget, before you proceed, kindly do the following:

* Create a stylesheet with the `.css` extension in your project directory.
* Link the stylesheet with your HTML file within the `<head>` element. (As a reminder `<link rel="stylesheet" href="styles.css">`). Here, my stylesheet is named `styles.css`.

Now, open your stylesheet, type, and save the following:

```css
.button {
	width: 100%;
	margin: 8px 0;
	padding: 14px 20px;
	color: #ffffff;
	background-color: #1560bd;
	border: 0;
	cursor: pointer;
}
```

The buttons should have some feeling of life in them, but they are still all over the place. That means you have to declare a boundary that will restrict them to where you'll like them to be.

You'll start with the buttons within the form.

Here is what you'll do:

* Declare a width for the button parent.
* Add some margin and necessary styling.

Here, the parent for the buttons within the form is the `form` element itself which has 3 classes named `form`, `modal__content`, and `animate`. You'll use `modal__content` because this will increase the readability of the stylesheet.

Anyone who reads the stylesheet would know the styles are meant for modal content. This would not be the case if you were to use `.form`. The reader will have a hard time figuring out what type of form you are referring to in the codebase.

```css
.modal__content {
	width: 80vmin;
	margin: 0 auto 15% auto;    /* This applies margin to all four sides of the modal */
	border: 1px solid #888888;
	background-color: #fefefe;
}
```

Save your file, and refresh your browser.

![An incomplete modal design](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bu9v8ek35s2wo7whpm46.png)

Next, you'll take care of the image and the "X" sign.

From the final result, you'll recall that the avatar image is situated at the center of the form and the "X" sign is positioned at the top-right, know, that, the avatar image and the "X" sign are both situated in a single form row and if you would like to position the "X" at the top-right location, its parent should have a `position` property set to anything other than `static` (which is the default). But, (read on).

There is a challenge. You'll need to target this form row alone because you will not perform any positioning on other form rows. How would you solve this? So far, here is what you know:

* The form row containing the avatar image is indeed the _first_ form row.
* You'll need a position property value other than `static`.

To solve the first of these constraints, here is what you'll do:

* You'll target the first row using the `:first-child` pseudo-class.
* Next, you'll change the position to `relative`.

In your stylesheet, type the following (don't save, yet):

```css
.form__row:first-child {
	position: relative;
	text-align: center; /* This will put the image at the center of the form row. */
	margin: 24px 0 12px 0;
}
```

Next, as evident from the final result, the image is round, and its size reduced compared to its current state. To achieve the rounded shape, you'll use the `border-radius` property and for the size, take a guess, the `width` property.

In CSS:

```css
.form__avatar {
	width: 40%;
	border-radius: 50%;
}
```

That's it for the image, if you'd like, you can save and observe your result.

Next, is the "X" sign.

Since the first row already has the position set to `relative`, you'll need to do the following to position "X" in the desired location:

* Set its position to `absolute`.
* Align it with offset properties.
* Add a color.
* Increase its font size.
* Make it stand out.
* Change color and mouse pointer when user interacts with.

All these in code:

```css
.closeModal {
	position: absolute;
	top: 0;
	right: 25px;
	color: #000000;
	font-size: 35px;
	font-weight: bold;
}

.closeModal:hover,
.closeModal:focus {
	color: red;
	cursor: pointer;
}
```

Save and refresh, the "X" should look a lot better.

![An highlighted X sign of the modal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rae819u5jknnxv4xuy0q.png)

We are approaching the modal design in a top-down approach, so far, you've positioned the modal; styled the first row of the form.

Next, is the form labels and inputs.

The form label is bold, therefore the following will take care of that:

```css
.form__label {
	font-weight: bold;
}
```

From the final result, the form inputs occupy almost the entire width of the form, this means you'll need something like `width: 100%`, and some additional styling (like border, margin and padding) to make it stand out. Write the following:

```css
.form__input {
	display: inline-block;
	width: 100%;
	margin: 8px 0;
	padding: 12px 20px;
	border: 1px solid #cccccc;
    
    /* This is not complete, check below */
}
```

Save, and you'll realize that there is a _tiny_ problem, as shown in the image below.

![Overflow of form inputs in the modal design](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/670lkhb10plrgr3v4zfg.png)

The form inputs are crossing their boundary, this is not good for the design. To fix this, you'll need the `box-sizing` property and a value of `border-box`. Why? If you might ask. Here is why.

The reason the inputs are crossing their boundary is because of 3 reasons listed below:

* The inputs have a width of `100%`.
* The inputs have margin and padding values.
* The inputs have a border greater than zero.

All these add to the final computed width of the inputs, hence the width of the inputs is longer than you'll expect. It's not magic, it's how the CSS box model works.

To prove my point, __temporarily do the following__ to your stylesheet:

1. Change the padding value to `12px 0px;`. This will remove the left and right padding.
2. Change the border value to `0`. This will remove the padding on all sides of the form inputs.
3. Save your file, and refresh your browser. You'll realize that the input now plays nicely but it's invisible.
4. Now add the following: `outline: 1px solid red;`. We use an outline because it does not add to the width of the element.

Therefore, the styles for `.form__input` should match the following:

```css
/* This is TEMPORARY. It's meant to prove a point. */
.form__input {
	display: inline-block;
	width: 100%;
	margin: 8px 0;
	padding: 12px 0px;
	border: 0;
	outline: 1px solid red;
}
```

Refresh your browser, your form input should match the image below.

![Highlighted form inputs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cc8yluo5igdn002rltq9.png)

I hope this clears things up. Now, __undo the temporary steps taken earlier__ and let's continue.

Therefore, when you use `box-sizing: border-box;`, you are telling the browser to account for any border and padding values you specify for an element width and height and the content box (the default box-sizing) will shrink to absorb the extra width (which is what you want in this scenario).

In this regard, your _final_ styles for the `.form__input` class should match the following:

```css
.form__input {
	display: inline-block;
	width: 100%;
	margin: 8px 0;
	padding: 12px 20px;
	border: 1px solid #cccccc;
    box-sizing: border-box;
}
```

Save and refresh your browser and inputs should work as expected.

Still on the form itself. Next, you will style the modal footer. But before styling the modal footer as a whole, you'll apply styles to its element one at a time. The elements are the "Cancel" button and the "Forget password" link.

The next CSS code block gets the job done. Add it to your stylesheet and don't forget to save it before refreshing your browser.

```css
.cancelModal {
	width: auto;
	padding: 10px 18px;
	background-color: #aaaaaa;
}

.forgetpassword {
	padding-top: 16px;
}

.forgetpassword__link {
	padding: 0.3em;
}
```

It looks better, but it's still not in the state that you would like it to be, the reason being that in the final design, the "Cancel" and "Forget password" are aligned to the edges of the modal.

This is the part where you apply styling to the modal footer as a whole.

```css
.modal__footer {
	display: flex;
	flex-wrap: wrap;			/* Elements would move to a new line if necessary. */	
	justify-content: space-between;	 /* Space between the modal footer elements. */
	background-color: #f1f1f1;
}
```

The result in the browser shows you are almost done.

![An incomplete modal design](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wp92purjvavvls25iiro.png)

In its current stage, the form looks rigid. You'll need to apply some padding.

```css
.form__row {
	padding: 16px;
	overflow: auto;
}
```

Save and refresh and it should look better.

There you go, you are done with the modal, or, are you? Because at this stage, the modal is always in view (a modal should show based on human interaction), there is no indication that indeed it's a modal.

This means you have to do 3 things, which are:

* Add some styles to the modal to show its modal.
* Hide the modal.
* Provide a mechanism to show the modal.

You'll start with the first one &mdash; additional styles to the modal.

Note that you'll want the modal at the center of the page when it's active, therefore, you'll use `position: fixed`. Also, it has to appear over all other elements. `z-index: 1` would take care of this.

Here you go:

```css
.modal {
	width: 100%;
	position: fixed;
	top: 0;
	left: 0;
	height: 100%;
	z-index: 1;
	overflow: auto;
	background-color: rgba(0, 0, 0, 0.4);
	padding-top: 60px;
}
```

When you save your file and preview the result in the browser, you'll notice that you are almost done. Almost, because there are some changes that you need to make. 

Currently, your user would find it difficult to use the "Cancel" button and "Forget password" on smaller viewports, as shown in the screenshot below.

![A modal form in Firefox web browsers with the Developer Tools docked to the right](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ih01lvqetj1ol00bdxg1.png)

At this viewport size, it's best to make it easier for the user to click the button and links. There is no better way than to stack them. The next code block would take care of this.

```css
/**
 * This would target a viewport of 480px and less.
 */
@media screen and (max-width: 30em) {
	.cancelModal,
	.forgetpassword {
		width: 100%;
	}

	.forgetpassword__link {
		display: block;
		padding: 10px;
		outline: 1px solid #1560bd;
		text-align: center;
		text-decoration: none;
	}
}
```

If you've done everything right, you should have an output similar to the image below.

![A modal form in Firefox web browsers with the Developer Tools docked to the right](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ijf7fmomuvdgys3y2bc3.png)

Now, you are done with the modal, but it's still in view, you need to hide it and show it on demand because that is the nature of modals.

Go ahead and update the styles for the `.modal` class by adding the following:

```CSS
.modal {
    /* Previous styles remains the same */
    
    display: none; /* Add this */
}
```

The modal is hidden, when you press the "Open modal" button, nothing happens. Speaking of which, the width of the "Open modal" button is way longer than usual. The next block offers a fix.

```css
.openModal {
	width: auto;
}
```

Still, when you press the button, you get nothing. You'll need JavaScript to show the modal.

The logic behind the JavaScript is described below:

* Get the modal.
* Get the "Open modal", "Close modal" buttons, and the "Cancel modal" sign.
* Attach an Event listener that will open the modal to "Open modal".
* Attach an Event listener that will close the modal to "Close modal".
* Attach an Event listener that will _also_ close the modal to "Cancel modal".
* When the user clicks anywhere outside the modal, close the modal.

Now, create a JavaScript file in your project directory and, save it with the `.js` extension. Link it with your HTML file using the `<script>` tag.

For example, `<script src="script.js"></script>`. Here, my JavaScript file is saved with `script.js`, you can give your JavaScript file any name that you'd prefer.

When you are done, type the following:

```js
let modal = document.getElementById('modal');
let openModal = document.getElementById('openModal');
let closeModal = document.getElementById('closeModal');
let cancelModal = document.getElementById('cancelModal');

openModal.addEventListener("click", () => {
	modal.style.display = 'block';
});

closeModal.addEventListener("click", () => {
	modal.style.display = 'none';
});

cancelModal.addEventListener("click", () => {
	modal.style.display = 'none';
});

// When the user click anywhere outside
// the modal, close it.
window.onclick = (event) => {
	if (event.target === modal) {
		modal.style.display = 'none';
	}
}
```

Save your file and test it out. The modal should show when you click the "Open modal" button, and when you click anywhere outside the modal, the "X" sign or the "Cancel" button, the modal should go back to its hidden state.

It's all good. Meanwhile, the modal, in its current state, pops out suddenly when the user clicks on the "Open modal" button. It could use some animation to soften things up.

Switch back to your CSS file, and add the following:

```css
.animate {
	-webkit-animation: zoomit 0.6s;
	animation: zoomit 0.6s;
}

@-webkit-keyframes zoomit {
	from {
		-webkit-transform: scale(0);
	}
	to {
		-webkit-transform: scale(1);
	}
}

@keyframes zoomit {
	from {
		transform: scale(0);
	}
	to {
		transform: scale(1);
	}
}
```

That completes the modal. Save all your files and test them out.

## __A note on Accessibility__

The modal login form is completed, but know this: it is unusable when your users have JavaScript disabled. The question is: How do you cater to such users. Here are my suggestions:

* Perform a check for JavaScript availability, if this check fails, ensure the "Open modal" button links to another page that contains the login form.
* Disable the button and tell the user to enable JavaScript. I do not recommend this, but still, it's among your options in this situation.

## Other (non-JS) solutions

A quick search online reveals that indeed you can create a modal without JavaScript, they are listed below:

* [Popup/Modal without JS &mdash; CodePen](https://codepen.io/peiche/pen/vhqym)
* [Modal Dialog Driven Websites Without JavaScript](https://levelup.gitconnected.com/modal-dialog-driven-websites-without-javascript-16e858615780)

## __Demo__

The demo is available online at the following URL: https://ziizium.github.io/my-webdev-notes/modalLoginForm/

## __Code__

The code is available in the `my-webdev-notes` GitHub repo linked below.

{% github ziizium/my-webdev-notes %}

## __Conclusion__

This article explained how to create a modal by taking you through the journey of the thought process behind every coding decision. Armed with this knowledge, you are in a better position of creating your modal from scratch or modify what you've learned to suit your needs.

## __Credit__

Cover photo by [Mika Baumeister on Unsplash](https://unsplash.com/@mbaumi).

_Edited July 4, 2021: Grammar fix._