Skip to content

tgomilar/motion-components

Repository files navigation

npm size

motion-components

Drop-in web components with spring-physics animations. Works in any framework - or no framework at all.

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.

▸ Reveal elements on scroll  ▸ Hover/press/tilt responses  ▸ Character-by-character text effects  ▸ Parallax & scroll scenes  ▸ Sliders, dialogs, image comparisons & more

👉 Docs & Live Preview

Built with Motion and Lit. Full TypeScript types included.


Quick start

1. Install

npm install motion-components

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/dist/index.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/motion-components/dist/preload.css" />

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

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
Vue 3 config
// vite.config.js
vue({
  template: {
    compilerOptions: {
      isCustomElement: (tag) => tag.startsWith('motion-'),
    },
  },
})
Angular config
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-text-mask
motion-font

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

Code

Syntax-highlighted code display

motion-code    motion-code-inline

Import note: motion-code lives at motion-components/code-window and motion-code-inline at motion-components/code-inline. The subpath names differ from the tag names.


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/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.


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 run typecheck    # tsc --noEmit
npm run lint         # ESLint
npm run format       # Prettier
npm run check:preload # validate FOUC preload rules
npm run size         # bundle size budget check

Repo layout

src/
├── reveal/      entrance & transition effects
├── respond/     input-driven interactivity
├── text/        typography effects
├── scroll/      scroll-driven components
├── components/  ready-made widgets
└── code/        code-display components

See CONTRIBUTING.md for component authoring conventions.


License

MIT © Tanja Gomilar

About

Web components with spring physics animations. Drop into any HTML page or framework — no rewrites. Built around motion from the start, not retrofitted with it. Every component uses spring physics, interruptible animations, and composable primitives so interactions feel natural.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors