JavascriptAlpine.js

How to use View Transitions with Alpine.js

With the recent addition of the View Transitions API to browsers, animation on the web has become a lot easier, but how do you make use of it if you’re using a framework, like say, Alpine.js?

Well, there is a way you use it today, but it isn’t perfect. I’m hoping in the near future Alpine will support View Transitions out of the box, but until then, here’s how you can use it.

If you just want to see a demo, skip to the end.

Take this todo list component. What we want is that when a task is completed, it gets removed from the list.

<ul class="tasks" role="list" x-data="tasks()">
	<template x-for="(task, index) in tasks" :key="index">
		<li class="flex items-center gap-2">
			<button type="button" @click="remove(index)">Done</button>
			<input type="text" x-model="task.name" :id="`task_${index}_name`" />
		</li>
	</template>
</ul>
 
<script>
	function tasks() {
		return {
			tasks: [{ name: 'Buy milk' }, { name: 'Buy eggs' }, { name: 'Buy bread' }],
			remove(index) {
				this.tasks.splice(index, 1);
			},
		};
	}
</script>

Simple enough. But what if we want fade the task out and animate the tasks below it to move up to fill the space?

Enter View Transitions

The View Transitions API allows you manipulate the DOM and delegate the animation to the browser. Here’s how.

<script>
	// Make sure the browser supports View Transitions
	const canTransition = 'startViewTransition' in document;
 
	function tasks() {
		return {
			tasks: [{ name: 'Buy milk' }, { name: 'Buy eggs' }, { name: 'Buy bread' }],
			remove(index) {
				/**
				 * Move the action into a function to avoid repetition
				 * (more useful when you have more complex code)
				 */
				const removeTask = () => this.tasks.splice(index, 1);
 
				// Check if the browser supports View Transitions
				if (canTransition) {
					document.startViewTransition(removeTask);
					return;
				}
 
				// If not, just remove the task
				removeTask();
			},
		};
	}
</script>

Let’s breakdown how this works.

First, we need to check if the browser supports View Transitions. We do this by checking if the startViewTransition method exists on the document object.

<script>
	const canTransition = 'startViewTransition' in document;
</script>

Next, in the remove method of our component, we move the code that removes the task into a function. This just helps avoid repetition, especially if you have more complex code. It’s not a required step.

<script>
	function tasks() {
		return {
			remove(index) {
				const removeTask = () => this.tasks.splice(index, 1);
			},
		};
	}
</script>

Finally, if we can use View Transitions, wrap the removeTask function in the startViewTransition method. This tells the browser to animate the DOM changes that happen inside the function.

<script>
	function tasks() {
		return {
			remove(index) {
				if (canTransition) {
					document.startViewTransition(removeTask);
					return;
				}
 
				removeTask();
			},
		};
	}
</script>

Demo

See the Pen View Transitions with Alpine by Chris (@chrismademe) on CodePen.

Custom Animation

I’ve not explored it yet, but you don’t have to stick with what the browser gives you. View Transitions can be animated in CSS. MDN is good place to get started if you’re keen.