Skip to content

kidonng/animation-observer

Repository files navigation

animation-observer

Lightweight module to monitor DOM elements matching a CSS selector

Install

npm install animation-observer

Usage

import {observe} from 'animation-observer'

observe('div', (element) => {
	console.log(element.id, 'just slid into the DOM.')
})

API

declare function observe(
	selector: string | string[],
	initialize: (element: Element) => void,
	options?: {
		event?: 'start' | 'end' | 'cancel'
		duration?: string
		signal?: AbortSignal
		name?: string
	},
): AbortController

Recipes

Stop the observer

You can pass a AbortSignal to the signal option.

const controller = new AbortController()

observe('img', () => {
	console.log('An image just showed up!')
}, {
	signal: controller.signal,
})

controller.abort()

Listen to different events

By default, the function listens to the animationstart event, which triggers when a matching element "appears".

You can listen to a different event in the options. The most prominent usage is to check element "disappears":

observe('div', (element) => {
	console.log(element.id, 'left the party.')
}, {
	event: 'cancel', // `animationcancel`
})

Or execute a function after a duration:

observe('input:focus', () => {
	alert('Please fill in your answer quickly.')
}, {
	event: 'end', // `animationend`
	duration: '10s',
})

duration has different meaning depending on event:

  • For start, it does nothing
  • For end, it is a delay
  • For cancel, it is a timeout (default: 9999s a.k.a "infinity")

Caveats

  • By "appearing", it means animationstart and animationend events are fired when the element meets the following conditions:
    • Element matches the selector
    • Element is not display: none (visibility: hidden is fine)
  • By "disappearing", it means animationcancel event is fired when one of the following happens:
    • Element no longer matches the selector (may still be in the DOM)
    • Element is removed from the DOM
    • Element becomes display: none

Custom name

By default, the function generates a random class name using crypto.randomUUID().

You can specify a custom name in the options:

observe('[href="https://www.random.org/"]', () => {
	console.log('True randomness™️')
}, {
	name: Math.random().toString(36).slice(2),
})

Browser support

This module uses CSS @layer to avoid conflicting with existing styles, which is supported since:

  • Chrome & Edge 99
  • Firefox 97
  • Safari 15.4

Credits

The first prototype is inspired by @fregante.

Support for multiple listeners matching the same element in v2.1.0 is adapted from Refined GitHub.

See Also