In this article and the steps that follow, we’ll create a detailed dialog modal using various CSS animation and transition properties to create more engaging microinteractions.

The basics

In its most basic form, triggering a dialog necessitates only two elements: a button to open the dialog and the dialog itself. The button is linked to the dialog by using the showModal() method, which is a built-in method of the dialog element.

<div id="app">
  <div id="content">
    <button>Open Dialog</button>
    <dialog>
      <p>Hello World</p>
    </dialog>
  </div>
</div>
const button = document.querySelector('button');
const dialog = document.querySelector('dialog');

button.addEventListener('click', () => dialog.showModal());

Styling the dialog

To make our dialog modal pop a little more, we’ll remove the default border, add a border radius, and apply a drop shadow. Otherwise, you can treat your dialog element like any other element and style it accordingly.

dialog {
  border: unset;
  border-radius: 0.375rem;
  filter: drop-shadow(0 0.75rem 0.75rem #00000020);
}

Styling the backdrop

The backdrop is the standard overlay that appears behind the dialog. You’ll also encounter it when working with popovers. We can style it using the ::backdrop pseudo-element. In this example, we’ll set the background color to a semi-transparent black.

dialog::backdrop {
  background-color: #00000020;
}

Adding microinteractions

Now we’ve added a simple but very plain implementation of a dialog modal. To spice things up, we add the aforementioned microinteractions using CSS animation and transition properties to give the dialog a more engaging feel and some depth.

Setting root variables

Define a CSS variable for the duration of the animation and set it to 150ms or a value of your choice. If the user prefers reduced motion, respect their preference and set the duration to a less eye-straining value or 0ms.

:root {
  --animation-duration: 150ms;

  @media (prefers-reduced-motion) {
    --animation-duration: 0ms;
  }
}

Defining the animation

For this example, we’ll use one of the simplest animations available and fade in the dialog. We’ll define a keyframe animation called fade-in that will fade the dialog in from 0% to 100% opacity.

@keyframes fade-in {
  0% {
    opacity: 0;
  }
  100% {
    opactiy: 1;
  }
}

dialog {
  animation: fade-in var(--animation-duration) ease-out both;

  &::backdrop {
    animation: fade-in var(--animation-duration) ease-out both;
  }
}

Adding depth with transformations

To give the dialog a sense of depth, we’ll apply a perspective transformation to the #app element. This will bring the dialog into the foreground, while the #app element will fade into the background and its #content will become blurred.

Note, that we’ve employed @media (prefers-reduced-motion: no-preference) to only apply the perspective change, if the user has not set their preference to reduced motion.

body {
  background: #eee;

  &:has(dialog[open]) {
    overflow: hidden;

    @media (prefers-reduced-motion: no-preference) {
      #app {
        border-radius: 0.75rem;
        filter: drop-shadow(0 0.75rem 0.75rem #00000020);
        overflow: hidden;
        transform: perspective(100vw) translateZ(-3rem);
      }
    }

    #content {
      filter: blur(0.125rem);
    }
  }
}

Applying transitions

All that’s left now is to apply the appropriate transition properties to the #app and #content elements to animate the transformation and filter properties accordingly. To distinguish #app as a layer, consider also using a dimmed background color for the <body>.

#app,
#content {
  transition-property: transform, filter, border-radius;
  transition-duration: var(--animation-duration);
  transition-timing-function: ease-out;
}

#app {
  background: #fff;
}

Result

And that’s it 🎉 You’ve just implemented a nicely animated dialog modal into your page, respecting user preferences and using standard and common techniques and tools.

TL;DR

Learn how to create a detailed dialog modal using microinteractions. We’ll cover the basics, styling the dialog, adding microinteractions, and applying transitions properly.