Skip to content

Fade-in elements on scroll

Problem. Reveal sections as they enter the viewport, but only animate for users without reduced-motion.

Solution. Use inView and respect prefersReducedMotion.

ts
import { inView, animate } from '@bquery/bquery/motion';
import { prefersReducedMotion } from '@bquery/bquery/a11y';

const reducedMotion = prefersReducedMotion();

document.querySelectorAll<HTMLElement>('.reveal').forEach((el) => {
  inView(el, () => {
    if (reducedMotion.value) { el.style.opacity = '1'; return; }
    animate(el, { opacity: [0, 1], transform: ['translateY(20px)', 'translateY(0)'] }, { duration: 300 });
  }, { once: true });
});

Why it works. inView uses IntersectionObserver and only fires once per element when { once: true }; reduced-motion users skip the keyframe animation entirely.

Released under the MIT License.