DEV Community

Cover image for How to animate objects with Tailwind CSS and Alpinejs intersection observer
Michael Andreuzza
Michael Andreuzza

Posted on

How to animate objects with Tailwind CSS and Alpinejs intersection observer

Today's tutorial is about alpinejs Intersect plugin, a convenient wrapper for the Intersection Observer API, allowing you to easily react when an element enters the viewport. It's fun, and easy to use!

See it live and get the code

Getting started

I am assuming from here that you already have a project setup with Tailwind CSS and Alpinejs, otherwise, put something together, and come back, or just grab the code, that's why is there.

The intersection oberver plugin

As they mentioned on the Alpine.js site
You can use this plugin by either including it from a <script> tag or installing it via NPM:

You can include the CDN build of this plugin as a <script> tag, just make sure to include it BEFORE Alpine's core JS file.

<!-- Alpine Plugins -->
<script defer src=""></script>

<!-- Alpine Core -->
<script defer src=""></script>
Enter fullscreen mode Exit fullscreen mode


You can install Intersect from NPM for use inside your bundle like so:

npm install @alpinejs/intersect
Enter fullscreen mode Exit fullscreen mode

Then initialize it from your bundle:

import Alpine from 'alpinejs'
import intersect from '@alpinejs/intersect'

Enter fullscreen mode Exit fullscreen mode

Understanding the Basics

Before diving into the code, let's establish a basic understanding of the key concepts:

  • Intersection Observer: Allows you to execute a piece of JavaScript when an element enters or leaves the viewport (or another element).
  • Alpine.js x-intersect Directive: Alpine.js leverages this API through the x-intersect directive, enabling you to trigger functions when an element becomes visible or once it has been observed.

Rotating an image on visibility

The first block of HTML you've provided outlines how an image can be rotated using Alpine.js when it comes into view:

      x-data="{ degree: 0, target: 360, rotate() { let interval = setInterval(() => { if ( < { += 5; } else { clearInterval(interval); } }, 50); } }"
      class="perspective-container ..."
        :style="`transform: perspective(1000px) rotateY(${degree}deg)`"
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • x-data initializes the component state with a degree of rotation and a target degree. The rotate function increments degree until it reaches target, creating a rotation effect. -x-intersect.once="rotate()" invokes the rotate function when the element is observed for the first time. The .once modifier ensures this happens only once.
  • The :style binding applies the rotation dynamically to the img tag as the degree variable changes.

Tilting an image on visibility

The second snippet provides a similar functionality but with a twist—literally:

<section class="overflow-hidden">
  <div class="flex flex-col h-screen my-24">
      x-data="{ degree: 0, target: 30, animate() { let interval = setInterval(() => { if ( < { += 1; } else { clearInterval(interval); } }, 50); } }"
        :style="`transform: perspective(1000px) rotateX(${degree}deg)`"
        class="transition-transform duration-1000 w-64 ease-in-out md:w-full mx-auto rounded-3xl md:max-w-xl"
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • This example tilts the image on the X-axis, using a similar x-data setup and x-intersect directive as the first example.
  • The animate function gradually increases the degree of rotation, creating a tilt effect as the image becomes visible.

Implementing your own intersection observations

To leverage the Intersection Observer in your Alpine.js projects, follow these steps:

  • D*efine the State and Functions:* Use x-data to define the component's state and functions you wish to execute upon intersection.
  • Use x-intersect: Apply the x-intersect directive to the element you want to observe. Use modifiers like .once to control the behavior (e.g., execute only once or every time it enters the viewport).
  • Bind Styles or Attributes: Use Alpine.js's binding capabilities (e.g., :style or :class) to dynamically update the element based on the component's state.

Things that you can do with the intersection observer

The Intersection Observer API enables developers to perform a wide array of tasks by monitoring the visibility of elements. Here are some of the key uses:

  1. Lazy Loading of Images or Content: Improve page load times and reduce bandwidth by loading images or content only as they enter the viewport.

  2. Animation Triggers: Start animations or transitions when an element becomes visible, enhancing user engagement with dynamic effects.

  3. Infinite Scrolling: Implement infinite scrolling by adding more content to the bottom of the page as the user scrolls down, eliminating the need for pagination.

  4. Ad Impression Tracking: Accurately track when advertisements become visible on the page for more precise impression tracking and billing.

  5. Activity Monitoring: Detect when a user has paused scrolling over a particular section, useful for triggering interactions such as auto-playing videos.

  6. Reading Progress Indicators: Create a progress indicator that updates based on the visibility of sections of content or articles, showing the user their reading progress.

  7. Sticky Headers or Elements: Dynamically show or hide sticky headers or elements based on scroll position and element visibility.

  8. Conditional Loading or Functions: Load scripts or execute JavaScript functions conditionally, based on the visibility of elements, for optimized performance.

  9. Dynamic CSS Class Assignment: Automatically add or remove CSS classes from elements as they enter or leave the viewport, allowing for responsive style changes.

  10. Accessibility Enhancements: Improve accessibility by pausing animations or auto-playing videos when they are not in the viewport, reducing distractions for users.

Leveraging the Intersection Observer API allows for more efficient and performance-friendly web development practices, particularly for visibility-related functionalities.

Top comments (0)