<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/morphicons-any-stroke-icon-morphs-into-any-other-530fwxr2a" -->

---
title: morphicons: any stroke icon morphs into any other
description: morphicons is a React library for animating icon transitions using Procrustes-based optimal 2D similarity solving and polar-space interpolation. Unlike...
canonical: https://daily.dev/posts/morphicons-any-stroke-icon-morphs-into-any-other-530fwxr2a
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: morphicons: any stroke icon morphs into any other | daily.dev
og:description: morphicons is a React library for animating icon transitions using Procrustes-based optimal 2D similarity solving and polar-space interpolation. Unlike...
og:url: https://daily.dev/posts/morphicons-any-stroke-icon-morphs-into-any-other-530fwxr2a
og:image: https://api.daily.dev/og/posts/530fWxr2a.png
og:image:alt: morphicons: any stroke icon morphs into any other
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# morphicons: any stroke icon morphs into any other

**[Web Developement](https://daily.dev/sources/webdevelopement)** · [@guillermolg](https://daily.dev/guillermolg) · 2 min read · 1 upvotes · 0 comments

## Summary

morphicons is a React library for animating icon transitions using Procrustes-based optimal 2D similarity solving and polar-space interpolation. Unlike existing solutions, it requires no per-pair rotation groups or raw coordinate interpolation — just change the icon prop. It supports uncontrolled, controlled, and imperative modes, handles mid-flight interruptions with spring velocity preservation, emits clean SSR SVGs, and works with Lucide, Tabler, Heroicons, Iconoir, and shadcn icons out of the box. Ships as MIT-licensed ESM at 7.65 KB gzip with zero runtime dependencies.

## Content

[morphicons](https://www.morphicons.com)
I got tired of icon morphs that either need a hand-declared "rotation group" per pair, or interpolate raw coordinates and shear the shape in transit. So I built morphicons.

The whole API is: change the prop.

```
import { MorphIcon } from "morphicons/react";
import { Menu, X } from "lucide"; // data, not components

<button onClick={() => setOpen(o => !o)} aria-expanded={open}>
  <MorphIcon icon={open ? X : Menu} />
</button>
```

No wrappers, no `AnimatePresence`, no keys, no from/to pairs, no config. State lives outside; the animation is an implementation detail the component picks up when the prop changes.

Three modes if you need them: uncontrolled (above), controlled (`from`/`to` + `progress`, for gestures/scroll) and imperative (`ref.morphTo()` / `ref.set()`).

What I actually care about:

- **Rotations emerge.** It solves the optimal 2D similarity between the two shapes (Procrustes) and interpolates in polar space. arrow-right → arrow-down gives θ = 90° on its own. plus → x gives 45°. Nobody declares that anywhere.
- **Real interruptions.** A `morphTo` mid-flight re-plans from the current intermediate shape and preserves the spring's velocity. Click spam never jumps.
- **Clean SSR.** The server emits the exact static SVG — zero flash, zero layout shift. The runtime is born on hydration.
- **Drop-in for lucide-react**: `size`, `strokeWidth`, `absoluteStrokeWidth`, `color`, `className` and the rest of the svg props pass through. `aria-hidden` by default, `label` → `role="img"` + `<title>`. `prefers-reduced-motion` degrades to an instant swap.
- One global rAF for every instance on the page.

Works with Lucide, Tabler, Heroicons (outline), Iconoir and the shadcn icon registry — no per-library adapters, because it just eats a `d` string or Lucide's `[tag, attrs][]` shape. Requirement is that the icons are stroke-drawn on a shared grid (all of the above are 24×24); off-grid packs go through `fitIcon(icon, 32)` once at module scope.

MIT, zero runtime deps, ESM, 7.65 KB gzip for the React entry (react external). React >= 18 as optional peer.

Playground with a scrubber so you can freeze any morph mid-flight: https://www.morphicons.com

Repo: https://github.com/guillermolg00/morphicons

---

Tags: [#react](https://daily.dev/tags/react), [#web-animation](https://daily.dev/tags/web-animation)

[View this post on daily.dev](https://daily.dev/posts/morphicons-any-stroke-icon-morphs-into-any-other-530fwxr2a)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"DiscussionForumPosting","mainEntityOfPage":"https://daily.dev/posts/morphicons-any-stroke-icon-morphs-into-any-other-530fwxr2a","headline":"morphicons: any stroke icon morphs into any other","text":"morphicons is a React library for animating icon transitions using Procrustes-based optimal 2D similarity solving and polar-space interpolation. Unlike existing solutions, it requires no per-pair rotation groups or raw coordinate interpolation — just change the icon prop. It supports uncontrolled, controlled, and imperative modes, handles mid-flight interruptions with spring velocity preservation, emits clean SSR SVGs, and works with Lucide, Tabler, Heroicons, Iconoir, and shadcn icons out of the box. Ships as MIT-licensed ESM at 7.65 KB gzip with zero runtime dependencies.","url":"https://daily.dev/posts/morphicons-any-stroke-icon-morphs-into-any-other-530fwxr2a","datePublished":"2026-08-01T15:37:18.052Z","dateModified":"2026-08-01T15:37:37.702Z","author":{"@type":"Person","name":"Guillermo López","url":"https://daily.dev/guillermolg","image":"https://avatars.githubusercontent.com/u/85084558?v=4","description":"Full Stack developer","interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"EndorseAction"},"userInteractionCount":730}},"image":"https://media.daily.dev/image/upload/s--UldSMPUs--/f_auto/v1785598640/posts/530fWxr2a?_a=BAMAMicg0","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"isPartOf":{"@type":"WebPage","url":"https://daily.dev/squads/webdevelopement","name":"Web Developement"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Web Developement","item":"https://daily.dev/squads/webdevelopement"},{"@type":"ListItem","position":3,"name":"morphicons: any stroke icon morphs into any other"}]}
```

