Native HTML: Dialog boxes
Tags: html, css, a11y, design
Published: 2019-01-03 11:27:46

For years if you wanted to make a modal `dialog` box you'd have to make a div, hide it and then display it when the user did a certain action. This was easy to throw together but accessibility wasn't great, a common error was leaving elements of the `dialog` in the tab index meaning a user would have to tab through every element of the `dialog` before they could move on.

As you've probably worked out I'll be writing about the native [`dialog`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog) element and how I use it. At the time of writing, support is, unsurprisingly, not all that great. 

![support table](https://thepracticaldev.s3.amazonaws.com/i/lo3faeb6iir481a8fg0d.png)

## The `dialog` element

I always like to take a dive into Mozilla's dev site to help learn about new elements so here is how they describe it.

> The **HTML `<dialog>` element** represents a dialog box or other interactive component, such as an inspector or window.

OK, but what does that mean? The syntax looks simple enough so let's give it a go.

```javascript
<dialog open> Test dialog </dialog>
```

{% codesandbox v0jq1r5qo0%}

How it looks in a supported browser.

![Simple Example](https://thepracticaldev.s3.amazonaws.com/i/ii3trhtctai0xx9ccxbv.png)

And there we have it, thanks for read... Oh, we're not quite done yet. We need to interact with the `dialog`, having it there all the time really isn't that helpful. Mozilla gives us a usage example but no information to go with it, so let's look elsewhere. 

## The w3 spec

When in doubt head to the [spec](https://www.w3.org/TR/html52/interactive-elements.html#the-dialog-element) and sure enough we have 3 functions for interacting with the `dialog` and they each have descriptions.

>**dialog . show( [ `anchor` ] )**
Displays the dialog element.
The argument, if provided, provides an anchor point to which the element will be fixed.

>**dialog . showModal( [ `anchor` ] )**
Displays the dialog element and makes it the top-most modal dialog.
The argument, if provided, provides an anchor point to which the element will be fixed.
This method honors the autofocus attribute.

>**dialog . close( [ `result` ] )**
Closes the dialog element.
The argument, if provided, provides a return value.

## Putting this in practice

Now, this is my own way of putting this into practice if you think it shouldn't be done this way let me know.

With `label`s you have a `for` attribute that lets you point to an element, by ID, that you want the label to be connected with. This inspired me to have a `data-modal-for`, data because it's not a real attribute.
```html
<button data-modal-for="testDialog" open>Open modal</button>
<dialog id="testDialog">
  <h1>An example of a native Dialog element</h1>
  <p>This is a dialog box and, believe it or not, it's built into HTML, sure we needed some javascript to open it but hey, it's a start.</p>
  <button data-modal-for="testDialog" close>Close modal</button>
</dialog>
```

```css
dialog {
  border: none;
  border-radius: 2px;
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
  max-width: 60vw;
}
```

```javascript
const modalTriggers = document.querySelectorAll(`[data-modal-for]`);

for (let trigger of modalTriggers) {
  const modal = document.getElementById(trigger.dataset.modalFor);
  trigger.addEventListener('click', () => {
    trigger.hasAttribute('open') && modal.showModal();
    trigger.hasAttribute('close') && modal.close();
  });
}
```

{% codesandbox jz50o73pqv%}

Here's how it looks after pressing the button, in a supported browser.

![Dialog example](https://thepracticaldev.s3.amazonaws.com/i/zzjxug83xgqils5gl0oq.png)

## Explain the javascript

I'm going to presume you know what the javascript does so I'm going to explain why I've done it this way.

First, I select all the elements I've given the `data-modal-for` attribute to then I add eventListeners to them. I also give my `trigger` elements an `open` or `close` attribute to specify how they will change the `dialog`

I know that this means any dynamically created elements won't work out the box but this was still the best way I could think of. 

## Signing off

Let me know if you like these `things we can't really use yet but maybe one day` posts. I find the advancement of the platform interesting and enjoy sharing.

Thanks for reading 🦄🦄😀😀❤🦄