{"id":29436801,"url":"https://github.com/alloc/preact-in-motion","last_synced_at":"2025-07-18T16:01:54.549Z","repository":{"id":304272339,"uuid":"1018267883","full_name":"alloc/preact-in-motion","owner":"alloc","description":"Light, elegant animation plugin for Preact (powered by Motion.dev and WAAPI)","archived":false,"fork":false,"pushed_at":"2025-07-12T20:51:07.000Z","size":30,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-12T20:52:09.451Z","etag":null,"topics":["animation","javascript","motion","preact","typescript","waapi"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alloc.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-11T23:07:42.000Z","updated_at":"2025-07-12T20:51:10.000Z","dependencies_parsed_at":"2025-07-12T21:03:23.351Z","dependency_job_id":null,"html_url":"https://github.com/alloc/preact-in-motion","commit_stats":null,"previous_names":["alloc/preact-animate-plugin","alloc/preact-in-motion"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/alloc/preact-in-motion","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alloc%2Fpreact-in-motion","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alloc%2Fpreact-in-motion/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alloc%2Fpreact-in-motion/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alloc%2Fpreact-in-motion/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alloc","download_url":"https://codeload.github.com/alloc/preact-in-motion/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alloc%2Fpreact-in-motion/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265091732,"owners_count":23710032,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","javascript","motion","preact","typescript","waapi"],"created_at":"2025-07-13T05:02:23.843Z","updated_at":"2025-07-13T05:04:36.472Z","avatar_url":"https://github.com/alloc.png","language":"TypeScript","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# preact-in-motion\n\n[![NPM version](https://img.shields.io/npm/v/preact-in-motion.svg?style=flat\u0026colorA=080f12\u0026colorB=1fa669)](https://www.npmjs.com/package/preact-in-motion)\n[![License](https://img.shields.io/github/license/alloc/preact-in-motion.svg?style=flat\u0026colorA=080f12\u0026colorB=1fa669)](https://github.com/alloc/preact-in-motion/blob/main/LICENSE)\n[![Bundle size](https://deno.bundlejs.com/badge?q=preact-in-motion@latest)](https://bundlejs.com/?q=preact-in-motion)\n\nThis package uses the [Preact Options API](https://preactjs.com/guide/v10/options/) to introduce an `animate` prop to every native element (e.g. `\u003cdiv\u003e`, `\u003cspan\u003e`, `\u003cbutton\u003e`, etc.). It uses the `motion/mini` package to animate the elements. To understand which features of Motion are supported, see [this comparison table](https://motion.dev/docs/feature-comparison#comparison-table).\n\n[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/edit/vitejs-vite-4pdjtwqz?file=src%2Fapp.tsx)\n\n## Installation\n\nChoose your package manager, then install this package and the `motion` package.\n\n- **PNPM**\n\n  ```\n  pnpm add preact-in-motion motion\n  ```\n\n- **Bun**\n\n  ```\n  bun add preact-in-motion motion\n  ```\n\n- **Yarn**\n\n  ```\n  yarn add preact-in-motion motion\n  ```\n\n- **NPM**\n  ```\n  npm install preact-in-motion motion\n  ```\n\n## Usage\n\nAlways import the package, so it can install itself into Preact at runtime.\n\n```ts\nimport 'preact-in-motion'\n```\n\nNow you can define the `animate` prop on any **host element** (e.g. `\u003cdiv\u003e`, `\u003cspan\u003e`, `\u003cbutton\u003e`, including SVG elements).\n\n```tsx\n// Animate the opacity when a boolean changes on rerender.\n\u003cdiv animate={{\n  opacity: visible ? 1 : 0,\n}}\u003e\n```\n\nWhen the element's parent component is re-rendered, the keyframes will be diffed. If any keyframes are different, a new animation will be scheduled.\n\nAnimation options (e.g. `duration`, `ease`, etc) may be defined next to the keyframes. [See the Motion docs for details.](https://motion.dev/docs/animate#options)\n\n```tsx\nimport { easeInOut } from 'motion'\n\n\u003cdiv animate={{\n  opacity: visible ? 1 : 0,\n  duration: 1,\n  ease: easeInOut,\n}}\u003e\n```\n\n### Property-specific options\n\nYou may set a `transition` function to customize the animation options for each style property.\n\n```tsx\n\u003cdiv animate={{\n  opacity: visible ? 1 : 0,\n  transform: `scale(${visible ? 1 : 0.5})`,\n  transition: prop =\u003e ({\n    duration: prop === 'opacity' ? 1 : 0.2,\n  }),\n}}\u003e\n```\n\nAlternatively, the `transition` prop can be set to an object, with property-specific options.\n\n```tsx\n// Identical to the previous example.\n\u003cdiv animate={{\n  opacity: visible ? 1 : 0,\n  transform: `scale(${visible ? 1 : 0.5})`,\n  transition: {\n    duration: 0.2,\n    opacity: { duration: 1 },\n  },\n}}\u003e\n```\n\n### Lifecycle animations\n\nThe following event-driven animations are supported:\n\n- `initial`\n  Style values to be applied before mounting.\n- `update`\n  Animate when this element is re-rendered.\n- `enter`\n  Animate when this element is added to the DOM.\n- `leave`\n  Animate before this element is removed from the DOM. (must use `\u003cAnimatePresence\u003e`)\n- `whileHover`\n  Animate when this element is hovered on.\n- `whileFocus`\n  Animate when this element is focused.\n- `whilePress`\n  Animate when this element is pressed on.\n\n```tsx\n\u003cdiv animate={{\n  // Start out invisible.\n  initial: {\n    opacity: 0,\n  },\n  // Fade in when added to the DOM.\n  enter: {\n    opacity: 1,\n  },\n  // Scale up while hovered over.\n  whileHover: {\n    transform: 'scale(1.1)',\n    duration: 0.2,\n  },\n}}\u003e\n```\n\n### AnimatePresence\n\nTo animate an element before unmounting it, you must wrap the element or its parent component with an `\u003cAnimatePresence\u003e` element.\n\n```tsx\n\u003cAnimatePresence\u003e\n  {visible \u0026\u0026 (\n    \u003ch1\n      animate={{\n        // Fade out before unmounting.\n        leave: {\n          opacity: 0,\n        },\n      }}\u003e\n      Fade Into Obscurity\n    \u003c/h1\u003e\n  )}\n\u003c/AnimatePresence\u003e\n```\n\nIf toggling between 2+ elements, you must set a `key` prop on each element.\n\nAdditionally, you may use the `enterDelay` prop on `AnimatePresence` to force “enter animations” to wait. This delay is only applied when a “leave animation” is in progress, making it useful for smooth transitions between elements.\n\n```tsx\n\u003cAnimatePresence enterDelay={300}\u003e\n  {isHappy ? (\n    \u003cspan\n      key=\"happy\"\n      animate={{\n        initial: { transform: 'translateX(50px)', opacity: 0 },\n        enter: { transform: 'translateX(0)', opacity: 1 },\n        leave: { reverse: true },\n      }}\u003e\n      😄 I'm happy!\n    \u003c/span\u003e\n  ) : (\n    \u003cspan\n      key=\"sad\"\n      animate={{\n        initial: { transform: 'translateX(-50px)', opacity: 0 },\n        enter: { transform: 'translateX(0)', opacity: 1 },\n        leave: { reverse: true },\n      }}\u003e\n      😢 I'm sad...\n    \u003c/span\u003e\n  )}\n\u003c/AnimatePresence\u003e\n```\n\nYou may set `reverse: true` on the `leave` prop to copy keyframes from the `initial` prop.\n\n### Easing\n\nEasing functions are provided by the `motion` package.\n\n- **Spring animations** ([docs](https://motion.dev/docs/spring))\n\n  ```tsx\n  import { spring } from 'motion'\n\n  \u003cdiv animate={{\n    transform: 'scale(1.1)',\n    type: spring,\n    bounce: 1,\n    duration: 3,\n  }}\u003e\n  ```\n\n- **Easing functions** ([docs](https://motion.dev/docs/easing-functions))\n\n  The `ease` prop accepts a function, pre-defined string, or a cubic bezier array (e.g. `[0.25, 0.1, 0.25, 1]`).\n\n  ```tsx\n  import { easeInOut } from 'motion'\n\n  \u003cdiv animate={{\n    transform: 'scale(1.1)',\n    ease: easeInOut,\n  }}\u003e\n  ```\n\n  These easing functions can be imported from `motion`:\n  - `cubicBezier`\n  - `easeIn` / `easeOut` / `easeInOut`\n  - `backIn` / `backOut` / `backInOut`\n  - `circIn` / `circOut` / `circInOut`\n  - `anticipate`\n  - `steps`\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falloc%2Fpreact-in-motion","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falloc%2Fpreact-in-motion","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falloc%2Fpreact-in-motion/lists"}