# How to Create a Modal Dialog Using Traditional JavaScript and the HTML5 Dialog Element

> Learn to create modal dialogs with traditional JavaScript and the native HTML5 dialog element. Explore custom control versus built in accessibility.

- Repository: [Jisan Mia/dom-projects](https://github.com/jisan-mia/dom-projects)
- Tags: how-to-guide
- Published: 2026-03-04

---

**You can create a modal dialog using either a traditional custom implementation with a `<div>` and JavaScript or the native HTML5 `<dialog>` element, with the former offering full styling control and legacy support while the latter provides built-in accessibility features like focus trapping and ESC-key dismissal.**

The `jisan-mia/dom-projects` repository demonstrates both approaches to create a modal dialog, providing developers with a complete reference for implementing overlays that range from fully custom solutions to modern native browser APIs. Whether you need to support legacy Internet Explorer or want to leverage modern accessibility features, understanding both methods ensures you can choose the right implementation for your project requirements.

## Traditional Custom Modal Implementation

### Architecture and Core Files

The traditional approach in `projects/modal/` uses a standard `<div>` structure transformed into a modal through CSS and JavaScript. The implementation centers around three key files:

- **[`projects/modal/modal.js`](https://github.com/jisan-mia/dom-projects/blob/main/projects/modal/modal.js)** – Contains the reusable `modal()` function that handles open/close logic
- **[`projects/modal/modal.css`](https://github.com/jisan-mia/dom-projects/blob/main/projects/modal/modal.css)** – Defines `.modal-wrapper` and `.modal-content` classes for styling and animations
- **[`projects/modal/index.html`](https://github.com/jisan-mia/dom-projects/blob/main/projects/modal/index.html)** – Demonstrates the markup structure required for the modal

### The modal() Function

The `modal()` function in [`projects/modal/modal.js`](https://github.com/jisan-mia/dom-projects/blob/main/projects/modal/modal.js) provides a generic way to convert any wrapper element into a modal dialog. It accepts four parameters: the open button selector, the wrapper selector, the content selector, and a boolean for injecting a close button.

```javascript
// Initialize the modal
modal(".subscribe", ".subscribe-wrapper", ".subscribe-content", true);

```

The function performs four critical operations:

1. **Element Selection** – Captures references to the trigger button, wrapper overlay, and content container
2. **Class Application** – Adds `.modal-wrapper` and `.modal-content` classes that apply fixed positioning and centering
3. **Open Handler** – Attaches a click listener to the trigger that sets `wrapper.style.display = 'block'`
4. **Close Logic** – Optionally injects a "×" button, handles click-outside-to-close via `event.target == wrapper` detection, and hides the wrapper with `display = 'none'`

### CSS Styling and Animations

The [`projects/modal/modal.css`](https://github.com/jisan-mia/dom-projects/blob/main/projects/modal/modal.css) file defines the visual behavior of the custom modal. The `.modal-wrapper` class creates the overlay effect using fixed positioning that covers the entire viewport.

```css
.modal-wrapper {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 1000;
}

.modal-content {
  position: relative;
  background-color: #fff;
  margin: 10% auto;
  padding: 20px;
  width: 80%;
  max-width: 500px;
  border-radius: 8px;
  animation: slideDown 0.3s ease-out;
}

```

Because this approach uses standard `<div>` elements, you have complete freedom to define custom animations, transitions, and responsive behaviors without fighting against native browser defaults.

## Native HTML5 Dialog Element

### Built-in Modal Behavior

The `projects/dialog/` directory demonstrates the modern approach using the native `<dialog>` element. Unlike the custom implementation, the HTML5 dialog provides several accessibility features automatically:

- **Focus trapping** – When opened with `showModal()`, keyboard focus remains inside the dialog
- **Backdrop handling** – The browser renders a native backdrop that can be styled with the `::backdrop` pseudo-element
- **ESC key dismissal** – Pressing Escape automatically closes the modal without additional JavaScript

### JavaScript API

The [`projects/dialog/dialog.js`](https://github.com/jisan-mia/dom-projects/blob/main/projects/dialog/dialog.js) file shows the minimal JavaScript required to control the dialog. The API consists of two primary methods: `showModal()` to open and `close()` to dismiss.

```javascript
// projects/dialog/dialog.js
const showBtn = document.getElementById("show-dialog");
const dialog = document.getElementById("dialog");
const closeBtn = document.getElementById("close-dialog");

// Open the modal
showBtn.addEventListener("click", () => dialog.showModal());

// Close the modal
closeBtn.addEventListener("click", () => dialog.close());

```

The markup structure in [`projects/dialog/index.html`](https://github.com/jisan-mia/dom-projects/blob/main/projects/dialog/index.html) uses the `<dialog>` tag directly:

```html
<dialog id="dialog" class="subscribe-wrapper">
  <div class="subscribe-header">
    <h2>Be the first to know when new content is available</h2>
    <button id="close-dialog" class="dialog-close-btn">×</button>
  </div>
  
  <div class="subscribe-body">
    <p>Sign up to receive tips and tricks on how to create online designs</p>
    <form id="subscribe-form">
      <input type="email" placeholder="Your email address" required />
      <button type="submit" class="primary-button">Sign me up</button>
    </form>
  </div>
</dialog>

```

### Browser Support Considerations

The HTML5 `<dialog>` element requires modern browser support. It works in Chrome 37+, Edge (all versions), Firefox 53+, and Safari 15.4+. For older browsers, you must include a polyfill or fall back to the traditional custom modal approach demonstrated in `projects/modal/`.

## Comparing the Two Approaches

When deciding how to create a modal dialog, consider the following technical differences:

**Traditional Custom Modal (`projects/modal/`)**
- **Browser support**: Works in all browsers including Internet Explorer
- **JavaScript complexity**: Requires manual handling of open/close logic, outside clicks, and focus management
- **Styling flexibility**: Complete control over animations, transitions, and responsive behavior via CSS
- **Accessibility**: Must manually implement `aria-modal`, `aria-labelledby`, and focus trapping

**Native HTML5 Dialog (`projects/dialog/`)**
- **Browser support**: Modern browsers only (Chrome 37+, Firefox 53+, Safari 15.4+)
- **JavaScript complexity**: Minimal API surface with `showModal()` and `close()` methods
- **Styling flexibility**: Limited to browser defaults for backdrop and positioning, though `::backdrop` pseudo-element allows some customization
- **Accessibility**: Native focus trapping, ESC-key dismissal, and semantic dialog role built-in

## Summary

- The **traditional custom modal** in `projects/modal/` uses a `<div>` wrapper with the `modal()` function in [`modal.js`](https://github.com/jisan-mia/dom-projects/blob/main/modal.js) to handle display toggling, outside-click closing, and optional close button injection, offering full browser compatibility and styling control.

- The **HTML5 `<dialog>` element** in `projects/dialog/` leverages the native `showModal()` and `close()` methods with minimal JavaScript, providing built-in accessibility features like focus trapping and ESC-key dismissal, but requires modern browser support.

- Choose the **custom implementation** when you need to support legacy browsers or require complex custom animations, and choose the **native dialog** for simpler use cases where modern browser support is guaranteed.

## Frequently Asked Questions

### What is the difference between `showModal()` and `show()` for the HTML5 dialog element?

The `showModal()` method displays the dialog as a modal, blocking interaction with the rest of the page and rendering a backdrop, while `show()` displays the dialog non-modally without blocking page interaction or adding a backdrop. For true modal behavior as implemented in [`projects/dialog/dialog.js`](https://github.com/jisan-mia/dom-projects/blob/main/projects/dialog/dialog.js), always use `showModal()`.

### How does the traditional modal handle closing when clicking outside the content?

The `modal()` function in [`projects/modal/modal.js`](https://github.com/jisan-mia/dom-projects/blob/main/projects/modal/modal.js) attaches a click event listener to the wrapper element and checks if `event.target == wrapper`. When this condition is true—meaning the user clicked on the backdrop rather than the content—it sets `wrapper.style.display = 'none'` to hide the modal.

### Can I use CSS animations with the HTML5 dialog element?

Yes, though with limitations. You can animate the dialog itself using standard CSS transitions and keyframes, but the `::backdrop` pseudo-element has restricted animation capabilities in some browsers. For complex entrance and exit animations as shown in [`projects/modal/modal.css`](https://github.com/jisan-mia/dom-projects/blob/main/projects/modal/modal.css), the traditional custom modal approach provides more reliable control over every animation aspect.

### Is the HTML5 dialog element accessible for screen readers?

The native `<dialog>` element provides better accessibility defaults than a generic `<div>`, automatically applying the `dialog` role and managing focus trapping. However, you must still add proper `aria-labelledby` attributes pointing to the dialog title and ensure focus is set appropriately when opening. The custom modal in `projects/modal/` requires manual implementation of all ARIA attributes and focus management to achieve equivalent accessibility.