Documentation

Motion Components is a library of physics-based web components. Compose primitives to build natural, interruptible interactions.

Installation

Import once — all custom elements register themselves as a side effect:

Import a specific class if you need the TypeScript type or want to call methods:

No bundler? Use the CDN directly:

Use only what you need

Every component ships as its own subpath export. Import a single tag and the bundler will only pull in that file — the rest of the library never reaches your bundle. Pay only for what you use.

Just one component:

A handful of components:

Import the class for typing or method access:

CDN, single component:

The full bundle (import 'motion-components') is convenient and brotli-compresses to ~20 KB for all 33 components. Per-component imports drop straight to the cost of just the tags you use.

Frameworks

Most frameworks work without configuration. A few need a small one-time setup so their compiler doesn't treat unknown tags as errors.

Import preload CSS and the library — works without configuration.

React 19 has full custom element support. Add preload and import in your entry file.

Configure custom elements in Vite and add preload in your entry file.

Add CUSTOM_ELEMENTS_SCHEMA and the preload stylesheet to angular.json.

Flash prevention

Web components are undefined when the HTML first renders. The browser treats <motion-flip-card> as a plain HTMLElement — its Light DOM children (slot="back" content, dialog panels, etc.) display as unstyled visible DOM before the JavaScript bundle arrives and calls customElements.define(). Slot-based components are especially sensitive because they carry visible Light DOM.

Solution — inline CSS in <head>

The only 100% reliable fix: inject a <style> tag in the document <head> that hides every component while it's :not(:defined). The CSS must be available synchronously before the first paint. A render-blocking CSS file (<link>) arrives after the HTML — there is a timing gap. Inline CSS has zero gap, zero flash risk.

Framework examples

Each example below inlines preloadCSS as a <style> tag in the document <head>. The import uses the motion-components/preload subpath — this file has zero side effects and evaluates cleanly in Node.js during SSR.

Inline CSS in main.tsx — works before first paint.

Inline in app/layout.tsx (App Router) or pages/_app.tsx.

Import in frontmatter, inline with is:inline.

Use useHead in app.vue or your root layout.

Inline in +layout.svelte via <svelte:head>.

Add preload.css to the styles array.

Alternative — CSS import

Simpler to set up, slightly less reliable: import the preload.css file. Most bundlers convert this to a render-blocking <link> — the browser won't paint until the CSS arrives. The gap between receiving the HTML and fetching the CSS is small but non-zero. Suitable for development and less flash-sensitive setups.

Or link it from a CDN in <head>: