Animating a dialog element using the View Transition API

rikschennink1 pts0 comments

Animating The Dialog Element Using View Transitions - Pqina

Pqina

Animating The Dialog Element Using View Transitions

June 23rd, 2026

In this article we look at animating the element using the View Transition API. We’ll follow progressive enhancement so it’s only used when supported and when the user allows animations to run.

Let’s take a look at the non-view-transition demo below. This demo uses the Invoker Commands API and doesn’t require any JavaScript. Click the button to open the dialog.

Hello World

Hello World<br>Close

As we can see below, the HTML is very straightforward and reveals the Invoker Commands API. The command attribute describes the action we want to run, and the commandfor attribute links a button to a target element using the id attribute of the target.

The "show-modal" command opens the dialog as a modal, and "request-close" close the modal. Note that we can also press the ESC key to close the modal.

button command="show-modal" commandfor="my-dialog">Hello Worldbutton>

dialog id="my-dialog"><br>span>Hello Worldspan><br>button command="request-close" commandfor="my-dialog">Closebutton><br>dialog><br>With the basic functionality set up, let’s look at adding the View Transitions API.

Adding The View Transitions API

Using the view transitions API we can create an animation that makes it seem like the dialog originated from the button, this creates a visual relationship between the two elements, helping communicate intent.

I’m currently implementing this in FilePond v5 to better communicate the relationship between an input source button and the modal that it triggers. An example of this would be a camera input button that allows you to use your webcam or phone camera to upload a photo.

The button below triggers a dialog using View Transitions. Please note that it doesn’t do so if your browser doesn’t support view transitions or if you’ve configured your system to reduce motion.

Hello World

Hello World<br>Close

Let’s look at the JavaScript code.

// these are basic helper functions to set the viewTransitionName style property<br>function clearTransitionName(...targets) {<br>targets.forEach(target => target.style.viewTransitionName = '');

function setTransitionName(target, name) {<br>target.style.viewTransitionName = name;

// don't run code if user prefers no animations, or if view transitions not supported<br>const userAcceptsMotion = matchMedia('prefers-reduced-motion').matches;<br>const browserSupportsViewTransitions = document.startViewTransition;<br>if (userAcceptsMotion && browserSupportsViewTransitions) {

// here we get the element references for easy of use later<br>const button = document.getElementById('my-button');<br>const buttonLabel = button.querySelector('span');

const dialog = document.getElementById('my-dialog');<br>const dialogTitle = dialog.querySelector('span');

// we set the initial view transition names, we'll move these to the dialog when the transition starts<br>setTransitionName(button, 'panel');<br>setTransitionName(buttonLabel, 'title');

// here we intercept events that open the modal<br>dialog.addEventListener('command', (e) => {

// only deal with the "show-modal" command<br>if (e.command !== 'show-modal') {<br>return;

// don't execute the default browse "show-modal" logic, we'll run it ourselves when we've started the view transition<br>e.preventDefault();

// here we start the "open dialog" view transition<br>document.startViewTransition(() => {

// move the transition names from button to dialog<br>clearTransitionName(button, buttonLabel);<br>setTransitionName(dialog, 'panel');<br>setTransitionName(dialogTitle, 'title');

// now we run the "show-modal" logic<br>dialog.showModal();<br>});<br>});

// here we intercept events that close the modal<br>dialog.addEventListener('cancel', (e) => {

// don't execute the default browser action<br>e.preventDefault();

// here we start the "close dialog" view transition<br>document.startViewTransition(() => {

// move the transition names from dialog to button<br>clearTransitionName(dialog, dialogTitle);<br>setTransitionName(button, 'panel');<br>setTransitionName(buttonLabel, 'title');

// now we run the "close" logic<br>dialog.close();<br>});<br>});<br>Some loose ends to discuss.

We use the request-close command instead of the close command as the close command doesn’t trigger the "cancel" event.

We animate the button and the button label separately. The button is transitioned towards the dialog panel shape, and the button label is transitioned towards the dialog title shape. If we’d transition the button as a whole the text in the button is scaled as well, which doesn’t look great.

The CSS below prevents the user from scrolling the page while the dialog is open.

dialog {<br>overscroll-behavior: contain;

dialog::backdrop {<br>overflow: hidden;<br>overscroll-behavior: contain;

You can tune the transition animations to your liking using the various ::view-transition pseudo elements.

That’s it!

I share web dev tips on Bluesky, if you found this interesting and want to learn more, follow me thereBluesky

Or join...

dialog button view transition close modal

Related Articles