npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

motion-components

v1.5.0

Published

Framework-agnostic web components for animated UI, powered by spring physics. Built on Motion and Lit.

Readme

motion-components

Drop-in web components for animated UI, powered by spring physics. Works in any framework, or with none.

Architected with animation as a core concern from day one - not bolted on as an afterthought. Every component leverages spring physics, interruptible animations, and composable primitives to deliver interactions that feel natural and responsive.

👉 Docs & Live Preview

Built with Motion and Lit. Full TypeScript types included.


Quick start

1. Install

npm install motion-components@^1

2. Import & use

// Import all components
import 'motion-components'

// Import separate components (tree shakable)
import 'motion-components/motion-reveal'
import 'motion-components/motion-hover'
import 'motion-components/motion-stagger'

// Prevent content flash before animations run
import 'motion-components/preload.css'
<motion-reveal>
  <h1>Animates in when scrolled into view</h1>
</motion-reveal>

<motion-hover scale="1.05">
  <button>Hover me</button>
</motion-hover>

<motion-stagger interval="0.06">
  <p>First child</p>
  <p>Second child</p>
  <p>Third child</p>
</motion-stagger>

CDN - no build step

<script type="module" src="https://cdn.jsdelivr.net/npm/motion-components@1/+esm"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/motion-components@1/dist/preload.css" />

<motion-reveal>
  <h1>Animates in when scrolled into view</h1>
</motion-reveal>

CommonJS

require('motion-components') works on Node 20.19+, 22.12+ and 23+. Jest needs ES module support turned on.


Framework setup

| Framework | Config needed? | | -------------------------------- | ------------------------------------------------------------------------------------------------- | | Astro, Svelte, Solid, Preact | None | | React | Use React 19+ (native web component support). React 18 has limited support - upgrade if possible. | | Vue 3 | Tell the compiler to treat motion-* as custom elements | | Angular | Add CUSTOM_ELEMENTS_SCHEMA | | Plain HTML | Use the CDN script tag above |

// vite.config.js
vue({
  template: {
    compilerOptions: {
      isCustomElement: (tag) => tag.startsWith('motion-'),
    },
  },
})
import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core'

@Component({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class MyComponent {}

Components

Reveal 🔗

Entrance & transition effects

motion-reveal motion-stagger motion-blur motion-blur-in

Respond 🔗

Input-driven interactivity

motion-hover motion-press motion-magnetic motion-tilt

Text 🔗

Typography & character effects

motion-split motion-typewriter motion-counter motion-scramble motion-ticker motion-words motion-curve motion-circle motion-arc motion-headline motion-glitch motion-gravity motion-liquid motion-perspective motion-stretch motion-swap motion-text-mask motion-font motion-marker motion-underline motion-strike motion-ring

Icons 🔗

Animated and state-morphing icons

motion-icon motion-icon-state

Scroll 🔗

Scroll-driven animation

motion-parallax motion-scene

Components 🔗

Ready-made interactive components

motion-slider motion-gallery motion-dialog motion-countdown motion-spotlight motion-progress motion-image-compare motion-flip-card motion-theme-toggle motion-theme-icon

Charts 🔗

Animated bar, line, pie and donut charts

motion-chart motion-pie motion-sparkline

Code 🔗

Syntax-highlighted code display

motion-code motion-code-inline


JavaScript API

Every animation component implements the same playback interface, so you can drive animations imperatively:

const el = document.querySelector('motion-typewriter')

await el.play()   // start if idle/finished, resume if paused
el.pause()        // freeze in place
el.finish()       // jump to the end state
el.cancel()       // reset to the initial state

el.playState      // 'idle' | 'running' | 'paused' | 'finished'
await el.finished // per-run promise, resolves on finish or cancel

Components emit motion-start, motion-finish, and motion-cancel events (bubbling and composed), so you can also listen at any ancestor:

document.addEventListener('motion-finish', (e) => console.log(e.target, 'done'))

Input-reactive components (motion-hover, motion-press, motion-magnetic, motion-tilt) expose a disabled property/attribute instead — set it to make them settle and stop responding to input.

Global controls

import { pauseAll, resumeAll, cancelAll } from 'motion-components'

pauseAll()          // pause every running animation, disable input-reactive components
resumeAll()         // resume what pauseAll paused, re-enable what it disabled
cancelAll()         // reset everything to its initial state

pauseAll(sidebar)   // all three accept a root node to scope the effect

When prefers-reduced-motion: reduce is set, play() skips straight to the final state — the finished promise and events still fire, so control flow keeps working.


Flash prevention (FOUC)

Web components upgrade asynchronously, so content can flash before animations are ready. Choose your prevention method:

Static stylesheet

import 'motion-components/preload.css'

CDN link

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/motion-components@1/dist/preload.css" />

Programmatic

import { preload } from 'motion-components'
preload(['motion-reveal', 'motion-split', 'motion-dialog'])

Call preload() with no arguments to cover all preload-registered components.

Raw CSS string (for Astro, Svelte, etc.)

import { preloadCSS } from 'motion-components'
// inject preloadCSS into your framework's <head> mechanism

Which components need preloading? Only those that hide content on initialization - reveal, text, stagger, dialog, and a few widgets. The build validates preload entries automatically via npm run check:preload.


Using with AI

AI assistants write better code from the current docs than from what they learned in training. Point yours at:

  • llms.txt: every component, docs page and recipe, with one line each
  • llms-full.txt: every attribute, event, slot and CSS custom property in one file
  • Any docs page as Markdown: add .md to its address, for example motion-marker.md

The package also ships editor data in dist/: custom-elements.json, VS Code custom data and web-types.json for JetBrains IDEs. Using with AI has a rules block to paste into AGENTS.md or CLAUDE.md, and the editor setup.


Why motion-components?

  • Motion-first. Built around animation from the start, not retrofitted.
  • Spring physics by default. No linear easing, no jank.
  • Interruptible. Interactions never queue or stutter - even mid-animation.
  • Per-component imports. Each component is a standalone subpath export - no dead weight, no bundler magic required.
  • Composable. Shared primitives instead of reimplemented animations.
  • Accessible. Honors prefers-reduced-motion. Keyboard-navigable.

Development

npm install           # install dependencies
npm run build         # build library to ./dist
npm run dev           # rebuild on file change
npm test              # browser tests
npm run typecheck     # tsc --noEmit
npm run lint          # ESLint
npm run format        # Prettier
npm run check:preload # validate FOUC preload rules
npm run check:exports # validate subpath exports
npm run check:ssr     # import every entry in Node
npm run size          # bundle size budget check

Repo layout

src/
├── reveal/      entrance & transition effects
├── respond/     input-driven interactivity
├── text/        typography effects
├── icons/       animated and state-morphing icons
├── scroll/      scroll-driven components
├── components/  ready-made widgets
├── charts/      data visualization
├── code/        code-display components
├── utils/       shared helpers
└── test/        shared test helpers

See CONTRIBUTING.md for component authoring conventions.


Documentation

www.motion-components.dev


Showcase

Showcase 🔗 · Parallax 🔗 · Scene 🔗 · Motion Font 🔗


License

MIT © Tanja Gomilar