Building a modal popup with pure JavaScript

Anton Ioffe - August 30th 2023 - 19 minutes read

Understanding Modal and Popup

Let's begin by briefly defining and differentiating between a modal and a popup - two terms that are often interchanged but differ significantly by their inherent nature and the level of user interaction they demand.

Comparing Modals and Pop-ups

A modal, also known as a child window, is a user interface element that obtains user engagement before allowing further actions. It often appears on center screen, often in the form of a request like a sign-in prompt or a cookie acceptance alert.

On the flip side, a popup is a secondary browser window that opens without the user's initiation. Unlike modals, popups do not prevent user actions. Appearing often as newsletters or notifications, they are secondary to the main user flow.

The following code helps better understand these differences.

Modal:

// Creating a modal that requires user interaction before further actions
const modal = document.getElementById('myModal');
const btn = document.getElementById('myBtn');
const span = document.getElementsByClassName('close')[0];

// Opens modal on button click
btn.onclick = function() {
  modal.style.display = 'block';
}

// Closes modal on 'x' click
span.onclick = function() {
  modal.style.display = 'none';
}

Popup:

// Creating a popup without user's initiation
window.open('http://example.com', '_blank', 'height=500, width=400');

Types of Modals and Their Uses

Modals can be further subcategorized into three: Modal popups, Dialog boxes, and Popovers. Modal popups demand user attention, dialog boxes request user input without forcefully halting user interaction, and popovers provide auxiliary, often contextual information, which users can dismiss at will.

The following code snippets demonstrate their distinct applications.

Modal Popup:

// A modal popup example in vanilla JavaScript
const modalPopup = document.querySelector('#modal-popup');
const openBtn = document.querySelector('#open-btn');

// Shows the modal popup
openBtn.addEventListener('click', () => {
  modalPopup.style.display = 'block';
});

Dialog Box:

// A dialog box example in vanilla JavaScript
const dialog = document.querySelector('#dialog');
const openDialogBtn = document.querySelector('#open-dialog-btn');

// Opens the dialog box
openDialogBtn.addEventListener('click', () => {
  dialog.showModal();
});

Popover:

// Pure JavaScript implementation for a popover
const popover = document.querySelector('.popover');
popover.addEventListener('mouseenter', function() {
  popover.title = 'Popover title: And here"s some helpful content. Engaging, isn"t it?';
});

Advantages and Disadvantages of Modals

While modals have their advantages, their misuse can obstruct user flow and negatively influence the user experience, causing issues with SEO as web crawlers may stumble upon indexing those modals. This was backed up in a study by UIE.

However, when executed right, modals can generate an optimal user experience. They are the perfect tool when it's necessary to obtain user action or when it's key to ensure the user comprehends essential information. A different study by Norman Group backs this up.

Developing effective window dialogs like modals and popups requires you to understand user behavior and the functionalities the website offers. This understanding married with the judicious usage of such dialogs can foster an effective and engaging user experience.

Types of Modals and Popups in JavaScript

Popups and modals play a significant role in shaping the user experience of a web application. With JavaScript and TypeScript, there's an array of options for their implementation, depending on various unique requirements.

The most commonly used popup in JavaScript is the Alert Box. Alert boxes are typically used to convey a brief message to the user and have only a single button, usually 'OK'. They are modal in nature, meaning they demand immediate attention from the user.

// using an alert box
alert('This is an alert message!');

Next is the Confirm Box. These boxes require user interaction before further action can be taken. Like alert boxes, confirm boxes are also modal and feature two buttons, namely, 'OK' and 'Cancel'.

// using a confirm box
let userResponse = confirm('Are you sure you want to proceed?');

The third type of popup available in JavaScript is the Prompt Box. These dialog boxes are designed to receive user input and are accompanied by two buttons - 'OK' and 'Cancel'. Prompt boxes also exhibit modal behavior.

// using a prompt box
let name = prompt('Please enter your name', 'User');

On the topic of dialog boxes, they fundamentally divide into two basic types: Modal Dialog Boxes and Modeless Dialog Boxes.

A Modal Dialog Box requires immediate attention from the user. The rest of the application becomes inaccessible until this dialog is closed. It's significantly used to acquire crucial user input. Here is how you can set up a Modal Dialog Box in JavaScript:

// Opening a modal dialog box
let dialogBox = window.showModalDialog('dialog.html');

Contrasting this, a Modeless Dialog Box permits interaction with other parts of the application while remaining open. It's beneficial in processes that need sporadic attention, such as spell-checking. Here's how one can create a Modeless Dialog Box:

// Creating a modeless dialog box
let modelessDialog = window.open('dialog.html');

Lastly, we distinguish between a Toast and a Modal. While both have uses in displaying small amounts of information, they function in different contexts.

A Toast notification is typically employed for system messaging. It's displayed for a specific amount of time and then disappears automatically. Here's a simple toast notification created in JavaScript:

// A simple toast in pure JavaScript
let toastElement = document.createElement("div");
toastElement.textContent = 'This is a toast message!';
document.body.append(toastElement);
setTimeout(() => toastElement.remove(), 2000);

Modals, conversely, require manual action to be dismissed. These dialog boxes are blocking in nature and commonly employed in alerts, confirmations, and user input gathering, as seen in the examples above.

// displaying a modal
alert('Urgent! Please acknowledge this alert!');

Given this understanding, engage with the following challenge: How would you adapt the above code examples to create a custom modal dialog that collects and validates user input, using both JavaScript and TypeScript?

Creating Popups and Modals in JavaScript

Building Modal with JavaScript

One doesn't need any libraries or frameworks to build a modal popup using pure JavaScript. First, let's sketch the modal window which will be triggered via a button click event. We start with a line of HTML to designate the button used to initiate the modal.

<!-- Button element -->
<button id='openModalButton'>Open Modal</button>

Then, using JavaScript, we identify the button by its id. Then, a div element is created, a class of 'modal' is added to it and it is appended to the body of the web document.

const openModalButton = document.getElementById('openModalButton');

if(openModalButton){
  const modalDiv = document.createElement('div');
  modalDiv.classList.add('modal');

  document.body.appendChild(modalDiv);

  openModalButton.addEventListener('click', () => {
    modalDiv.classList.add('show');
  });

  window.addEventListener('click', (event) => {
    if(event.target === modalDiv){
      modalDiv.classList.remove('show');
    }
  });
}

Here we're responsive to a button click—unfurling a modal window. Please note, 'show' here is a CSS class that controls the visibility of the modal popup.

Popup on Page Load

To trigger the popup on page loading, use the window.onload event. You could exhibit a sign-up form via that modal upon page load. The following example illustrates this further with the previously introduced modalDiv.

window.onload = () => {
  modalDiv.classList.add('show');
};

Avoid Alert for Message Display

Custom modals permit greater flexibility as opposed to using JavaScript's built-in alert function, primarily because of their ability to adapt to CSS style guidelines. As a workaround, see the below custom modal creation, where modalDiv is supplemented with a message paragraph.

const messageParag = document.createElement('p');
messageParag.textContent = 'This is my message';

modalDiv.appendChild(messageParag);

This alternative notably enhances UX by providing stylish error messages or form confirmations.

Image Manipulation in Modal

Including images in your modals refines their appeal. The following snippet showcases an image addition to the pre-existing modalDiv.

const modalImg = document.createElement('img');
modalImg.src = 'path/to/image';
modalImg.alt = 'Image Description';

modalDiv.appendChild(modalImg);

A typical use case could be product image popups for e-commerce sites.

The whole JavaScript code for generating Modal Popup

Finally let's see the whole JavaScript code for creating and managing modal popup based on previous parts.

const openModalButton = document.getElementById('openModalButton');

if(openModalButton){
  // Defining a div element for modal
  const modalDiv = document.createElement('div');
  modalDiv.classList.add('modal');

  // Adding modal to the body of the web document
  document.body.appendChild(modalDiv);

  // Showing modal on button click
  openModalButton.addEventListener('click', () => {
    modalDiv.classList.add('show');
  });

  // Hiding modal when clicked outside of it 
  window.addEventListener('click', (event) => {
    if(event.target === modalDiv){
      modalDiv.classList.remove('show');
    }
  });

  // Message in modal
  const messageParag = document.createElement('p');
  messageParag.textContent = 'This is my message';
  modalDiv.appendChild(messageParag);

  // Image in modal
  const modalImg = document.createElement('img');
  modalImg.src = 'path/to/image';
  modalImg.alt = 'Image Description';
  modalDiv.appendChild(modalImg);

  // Page load event
  window.onload = () => {
    modalDiv.classList.add('show');
  };
}

Challenge

Your mission is to extend the functionality of the modal. Try to develop an extra feature for it - devise a modal that incorporates a close button inside the modal content. Engage the knowledge you gained from the previous sections, now it's time to apply them in a creatively different way. Get creative, remember practice should inform your course of action. All the best, and happy coding!

Form and Div Related Concepts

In this section, we'll examine simple but concrete examples of creating a pop-up div and including a form within that div using JavaScript. We'll also see how to trigger the pop-up upon specific user action, like the click of a button.

Please note that handling styles inline in JavaScript, as we are doing here for the sake of simplicity, is not the best practice in a real-world scenario. Ideally, you should define styles in a separate CSS file. You'll also notice the use of HTML in our code samples. While HTML is technically a markup and not a programming language, it's integral to the web development process and simply can't be avoided in this context.

Let's start by defining a DOM element in our HTML code. Here is a simple way to do this:

    <!-- A div with id 'popupDiv' which is hidden by default -->
    <div id='popupDiv' style='display: none;'> This is a popup </div>

In our JavaScript, we use the getElementById method and select this div. After selecting, we change its display property to 'block', thus making it visible. The JavaScript for this is demonstrated below:

    // Javascript to show the popup
    let popupDiv = document.getElementById('popupDiv');
    popupDiv.style.display = 'block';

In this piece of code, the div with id popupDiv is initially hidden from the page (display: 'none';).

Next, let's include a form within this popup div:

    <!-- HTML structure with a form within the popup div -->
    <div id='popupDiv' style='display: none;'>
        <form id='form'>
            <!-- Basic form example -->
            <label for='myInputField'>Name:</label><br>
            <input type='text' id='myInputField' name='myInputField'><br>
        </form>
    </div>

With this setup, a form has been inserted within the div which is going to pop up. The JavaScript part remains the same - upon setting display: block for the div, the form will also pop-up.

We can also manage when precisely the pop-up appears, for instance on a specific event such as the click of a button:

<button id='showPopup'>Show Popup</button>
<div id='popupDiv' style='display: none;'> This is a popup </div>
let button = document.getElementById('showPopup');
let popupDiv = document.getElementById('popupDiv');

button.addEventListener('click', () => {
    popupDiv.style.display = 'block';
});

Now the pop-up div and the embedded form only appear when the user clicks the button.

These code snippets serve as a foundation to build upon for incorporating more complexity and customization. In the next evolutionary steps, you would ideally add a "close" button to the popup or even enable closing the popup when clicking outside of it. You could also enhance its appearance by incorporating animation, or improving the form's aesthetics. Integrating popup visibility with state management in frameworks like React or Vue is also a viable option. However, we won't delve deeper into those topics here, as our focus remains on basic popup creation. Let's summarize:

  • A pop-up div in JavaScript can be created by manipulating the display property of a predefined div from none to 'block'.
  • A form can be included within this pop-up by embedding the form HTML within the div HTML.
  • The pop-up can be made to appear on a specific action like the click of a button by adding an event listener to that button.
  • For stylistic definition, a separate CSS file is preferable over inline JavaScript.

Working with Alerts in JavaScript

Before diving into more complex forms of user interaction in JavaScript and TypeScript, we often start with the basics: alert, confirm, and prompt dialogs. For this, let's focus specifically on the prompt dialog and JavaScript's nuances with the alert function.

Prompt Box Usage

The JavaScript prompt function provides a simple way to interact with users. It displays a dialog box that prompts the user for input and returns the entered value.

Example:

// A simple prompt usage
let userName = prompt('Please enter your name');
console.log(`Hello, ${userName}!`); 

Please remember that the prompt function will return a string of the entered value or null if the user clicked the cancel button or closed the prompt dialog. Depending on the situation in your application, you may need to cast this return value to a different type or handle the null value.

Understanding Alert Blocking

Despite the simplicity of JavaScript's alert function, it is important to grasp one crucial aspect of how it works - it is blocking. What does this mean? When the alert function is called, it stops the execution of subsequent JavaScript code until the user clicks the "OK" button in the alert dialog.

Let's examine a quick example:

// code before alert
console.log('Before alert.');

// alert dialog
alert('Hello, world!');

// code after alert
console.log('After alert.');

In this example, 'After alert.' will not be printed to the console until the user acknowledges the alert dialog. This is the behavior of the blocking nature of the alert function.

Remember, while its simplicity makes it tempting to use for debugging, it can cause frustration in real-world scenarios due to this blocking nature. It is recommended to use console.log or a developer tool for debugging purposes instead.

In conclusion, JavaScript allows easy ways to interact with users through alert, prompt, and confirm but it's important to understand the nuances of each to avoid falling into common traps like blocking the execution of your code.

For those looking to delve deeper into this topic, consider investigating further the alternatives to these native JavaScript functions: libraries and browser APIs that provide more powerful and customizable user interaction tools without the blocking problem.

Handling Modal and Popup in HTML

Improve your website's user interaction with popups and modals. In this article, we'll explore how to implement these features using HTML and JavaScript.

Building a Popup Mixing HTML and JavaScript

To construct popups, begin by defining the HTML structure before implementing its functionality with JavaScript:

<button id="modalButton">Open Modal</button>

<div id="myModal" class="modal">
  <div class="modalContent">
    <span class="close">&times;</span>
    <p>Some text in the Modal..</p>
  </div>
</div>

With the HTML set up, you assign JavaScript to manage interactions. You fetch the modal element, the button acting as a trigger, and the element that prompts its closure. Afterward, you attach event listeners:

// Fetch the modal element
const myModal = document.querySelector('#myModal');

// Fetch the button that opens the modal
const modalButton = document.querySelector('#modalButton');

// Fetch the element that closes the modal
const closeBtn = document.querySelector('.close');

// Display the modal when the user clicks the button
modalButton.onclick = function() {
  myModal.style.display = 'block';
}

// Hide the modal when the user clicks on <span> (x)
closeBtn.onclick = function() {
  myModal.style.display = 'none';
}

// Hide the modal when the user clicks outside of it
window.onclick = function(event) {
  if (event.target === myModal) {
    myModal.style.display = 'none';
  }
}

Popup Messages in HTML

JavaScript supports the creation of alert boxes (popup messages). Consider a scenario where, after submitting a form, you desire to notify a user of successful completion. The alert() function provides a convenient method for accomplishing this:

alert('Form has been submitted successfully!');

In conjunction with alert(), confirm and prompt dialogs can present users with particular decisions or solicit specific information.

Positioning Modals in HTML

To center the modal in the screen, utilize the CSS properties position: fixed;, top: 50%;, and left: 50%;:

.modal {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

Crafting a Popup in HTML Without JavaScript

You can also construct a popup using solely HTML and CSS. To maintain the popup's state, employ a checkbox input element. Although this technique encompasses interactive HTML elements, no JavaScript code is necessary:

<input type="checkbox" id="popup">
<label for="popup" class="popupBackground">
  <div class="popup">Hello, I'm a Popup</div>
</label>
input[type="checkbox"] {
  position: absolute;
  opacity: 0;
}

input[type="checkbox"]:checked ~ .popupBackground {
  display: block;
}

.popupBackground {
  display: none;
}

.popup {
  margin: auto;
  padding: 20px;
  background-color: white;
  width: 30%;
  height: 30%;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border: 1px solid black;
}

In this example, revealing the popup depends on the state of the checked checkbox and the role of .popupBackground.

Challenge

With your understanding stretched, can you design a modal containing a form, validate this form, and submit it using JavaScript? Without referring back to these examples, work on this challenge, noting any difficulties you encounter. This task should further your appreciation of JavaScript's capabilities in manipulating interactions between forms and popups.

Advanced Concepts

TypeScript Modal Dialog

Creating modal windows can often become crucial as we venture towards feature-rich application development. Although TypeScript and JavaScript share resemblances when crafting a modal dialog, TypeScript has a noted upper hand via its strict typing feature. This particular attribute helps avoid common JavaScript errors, such as referencing an undefined variable or incorrectly typing an object property. TypeScript's supportive feature – providing early warnings, assists in circumventing such hindrances typical in JavaScript.

Here is a sophisticated, practical Modal Dialog application in TypeScript with annotations:

// ModalOptions type definition 
type ModalOptions = {
  onOpen: <T extends Event>(event: T) => void;
  onClose: <T extends Event>(event: T) => void;
};

// Modal class
class Modal {
  private dialog: HTMLDialogElement;
  private options: ModalOptions;

  // Modal class constructor
  constructor(dialogId: string, options: ModalOptions) {
    const dialog = document.querySelector(dialogId) as HTMLDialogElement;
    if (!dialog) {
      throw new Error(`Dialog with id ${dialogId} not found.`);
    }
    this.dialog = dialog;
    this.options = options;
  }

  // open modal dialog
  public show() {
    this.dialog.showModal(); 
    this.options.onOpen(new CustomEvent('open'));
  }

  // close modal dialog
  public close() {
    if (!this.dialog.open) return;
    this.dialog.close();
    this.options.onClose(new CustomEvent('close'));
  }
}

In this sample, we define a type ModalOptions, and a Modal class. The options type provides two event callbacks for the modal component: onOpen and onClose. When instantiated, the Modal class requires an id selector and a ModalOptions type option.

Showing and Hiding Pop-up Triggers

Modals often toggle visibility based on various user events: form submissions, button-clicks, or unique user behaviors. To exemplify, we put the TypeScript modal class into action, defining our modal and subsequently revealing it following a button-click event:

const myModal = new Modal('#myModal', {
  onOpen: (event) => console.log('Modal is shown', event),
  onClose: (event) => console.log('Modal is closed', event),
});

const showModalBtn = document.querySelector('#showModalBtn') as HTMLButtonElement;
showModalBtn.addEventListener('click', (_) => myModal.show());

In this instance, a click on showModalBtn triggers the show function from our myModal instance. For a modal to show or hide based on diverse user actions, say, a form submission, we can add an event listener, firing the modal's respective show or hide functions when the user action conditions are met.

Modal Trigger Mechanisms

Modal reveals aren't solely based on button-click events. They can be set to appear through other means, such as page load or a timed interval. Let's observe how non-button events - like checking the offline and online status of the browser - can be used to unveil a modal:

window.addEventListener('online', (_) => myModal.show());
window.addEventListener('offline', (_) => myModal.close());

In this instance, the modal pops up when the browser builds an internet connection. Subsequently, the modal disappears when the connection is interrupted. It may be wise to keep these listeners exclusive to each modal to prevent undesired behavior. This strategy showcases an ample range of potential triggers.

Challenges

Are you prepared to test your capabilities? Here's a challenge: Can you adapt the Modal class to support multiple modals on one page? Each must have distinct 'open' and 'close' events. Hint: Consider managing and referring to the various modals within your application structure.

The skilful blend of TypeScript's type safety and controlling modal trigger strategies can greatly enrich user-friendly web page experiences. By employing these advanced techniques and varied modal triggers, you have the liberty to experiment and enhance the interactivity, complexity of your user interfaces; ultimately propelling your web development efforts forward.

Design Aspects

In web development, one of the common requirements is to design and create floating popups. Floating popups are usually used to display additional information or to achieve user interaction without interrupting the primary user flow on the main web page. In context of HTML, CSS plays a crucial role in orchestrating the position, style and behavior of these floating popups.

When it comes to controlling the popup position, we primarily have two CSS properties that form the cornerstone of placement logic in HTML UI's - 'position' and 'z-index'.

The position CSS property sets how an element is positioned in a document, which enables us to place the floating popup anywhere on the web page. The top, right, bottom, and left properties then determine the final location of the positioned element. An element with position: fixed; for example, is positioned relative to the viewport, which means it always stays in the same place even if the page is scrolled.

Here's an example on position: fixed; for a popup. Imagine a simple 'Help' icon in your webpage, which shows a 'Help text' inside a popup when clicked.

// User clicks on a help button 
document.querySelector('.help-button').addEventListener('click', function(){
    const popup = document.querySelector('.help-popup');
    popup.style.position = 'fixed';
    popup.style.top = '50%';
    popup.style.left = '50%';
    popup.style.transform = 'translate(-50%, -50%)';
    // to center the popup in the middle of viewport
});

This JavaScript code snippet, sets the position of the popup in the center of the viewport when the help-button is clicked.

Moving on, the z-index CSS property controls the vertical stacking order of elements that overlap. As a result, it determines which element covers another one if they overlap. Elements with higher z-index cover those with a lower one.

Let's take an example of z-index: Suppose you have a modal and a floating popup on the same page and both of them have position fixed. Now, if you want the popup to be shown over the modal, you would need to take control of z-index.

// Assume we have a function to show modal and popup
function showModalAndPopUp(){
    const modal = document.querySelector('.modal');
    const popup = document.querySelector('.popup');

    // Setting position to fixed for both
    modal.style.position = 'fixed';
    popup.style.position = 'fixed';

    // Modal appears first, so it should have lower z-index
    modal.style.zIndex = '1';

    // Popup should appear over modal, giving it higher z-index
    popup.style.zIndex = '2';
}

This JavaScript snippet will ensure that the popup is always shown over the modal, regardless of the order in which they were added to the document.

While these CSS properties are at the heart of position, we also have many other concepts which aid in refining the user experience, such as transition and transform properties for controlling popup animations, box-model properties like margin, padding, border for refining the popup design among others.

Please remember throughout this section, our discussion was solely about the position of the popup. For a more complete guide on handling modals, popups including creating, closing, backdrops and more, refer to the 'Handling Modal and Popup in HTML' section.

Now that we have a good understanding of how CSScan be used to control the position and layering of a popup, it's time for a small challenge. Can you think of a scenario where even higher z-index does not render an element above another? Have you ever experienced such a thing? It's not a bug, it's a feature! Practicing what we've just learned, let's try solving this riddle.

Don't Get Left Behind:
The Top 5 Career-Ending Mistakes Software Developers Make
FREE Cheat Sheet for Software Developers