SVG Morph Animation Reference


Core Principle
Morph = animate attributes of the SAME element, not between different elements
<!-- ❌ Wrong: Different elements -->
<circle r="25" />
<rect width="50" height="50" />
<!-- ✅ Right: Same element, animate attributes -->
<rect width="50" height="50" rx="25">
<animate attributeName="rx" to="0" dur="1s" />
</rect>
The Process
Identify start/end shapes
Choose ONE element type that can represent both
Find attributes that change between the shapes
Animate those attributes
Common Morph Patterns
Circle ↔ Rectangle
Use <rect>
with rx
attribute
<!-- Circle: rx = half of width/height -->
<rect x="25" y="25" width="50" height="50" rx="25" />
<!-- Rectangle: rx = 0 -->
<rect x="25" y="25" width="50" height="50" rx="0" />
<!-- Animation -->
<rect x="25" y="25" width="50" height="50" rx="25">
<animate attributeName="rx" to="0" dur="1s" />
</rect>
Line ↔ Triangle
Use <polygon>
with same point count
<!-- Triangle: 3 distinct points -->
<polygon points="12 4, 20 16, 4 16" />
<!-- Line: collapse top point to baseline -->
<polygon points="12 16, 20 16, 4 16" />
<!-- Animation -->
<polygon points="12 16, 20 16, 4 16">
<animate attributeName="points" to="12 4, 20 16, 4 16" dur="1s" />
</polygon>
Rectangle ↔ Triangle
Use <polygon>
with 4 points (overlap for triangle)
<!-- Rectangle: 4 corners -->
<polygon points="0 0, 24 0, 24 24, 0 24" />
<!-- Triangle: move one point to overlap another -->
<polygon points="0 0, 24 24, 24 24, 0 24" />
<!-- Animation -->
<polygon points="0 0, 24 0, 24 24, 0 24">
<animate attributeName="points" to="0 0, 24 24, 24 24, 0 24" dur="1s" />
</polygon>
Point Count Rule
CRITICAL: Same number of points in start and end states
<!-- ❌ Breaks: 4 points → 3 points -->
<animate
attributeName="points"
from="0 0, 24 0, 24 24, 0 24"
to="0 0, 24 24, 0 24"
/>
<!-- ✅ Works: 4 points → 4 points -->
<animate
attributeName="points"
from="0 0, 24 0, 24 24, 0 24"
to="0 0, 24 24, 24 24, 0 24"
/>
Solution: Overlap points
Want 3 points? Make 2 points share same coordinates
"12 4, 20 16, 20 16, 4 16"
= triangle with 4 points
Path Morphing
Use <path>
with same command structure
<!-- Both paths need same commands -->
<path d="M10 10 L50 10 L50 50 L10 50 Z">
<animate attributeName="d" to="M10 10 L30 30 L50 50 L10 50 Z" dur="1s" />
</path>
Element Choice Guide
Morph Type | Best Element | Animate |
Circle ↔ Rectangle | <rect> | rx attribute |
Simple shapes | <polygon> | points attribute |
Complex curves | <path> | d attribute |
Size changes | Any element | width , height , r , etc. |
CSS vs SMIL Animation
SMIL (recommended for morphing)
<rect rx="25">
<animate attributeName="rx" to="0" dur="1s" fill="freeze" />
</rect>
CSS (limited support for morphing)
/* Only works for simple numeric attributes */
rect {
rx: 25;
transition: rx 1s;
}
rect:hover {
rx: 0;
}
Common Gotchas
Coordinate System
<!-- Coordinates must fit viewBox -->
<svg viewBox="0 0 24 24">
<polygon points="12 4, 20 16, 4 16" />
<!-- ✅ Fits -->
<polygon points="120 40, 200 160, 40 160" />
<!-- ❌ Outside viewBox -->
</svg>
Point Order Matters
<!-- Points animate in order: 1→1, 2→2, 3→3, 4→4 -->
<animate
attributeName="points"
from="0 0, 24 0, 24 24, 0 24"
to="12 0, 24 12, 12 24, 0 12"
/>
Path Command Compatibility
<!-- ❌ Different commands don't morph smoothly -->
<animate attributeName="d" from="M10 10 L50 50" to="M10 10 Q30 20 50 50" />
<!-- ✅ Same commands work better -->
<animate
attributeName="d"
from="M10 10 Q30 30 50 50"
to="M10 10 Q30 20 50 50"
/>
Practical Examples
Button State Changes
<rect rx="0" class="button-bg">
<animate attributeName="rx" to="8" dur="0.3s" begin="button.mouseenter" />
<animate attributeName="rx" to="0" dur="0.3s" begin="button.mouseleave" />
</rect>
Icon Transformations
<!-- Play button → Pause button -->
<polygon points="8 5, 8 19, 19 12">
<animate attributeName="points" to="8 5, 10 5, 10 19, 8 19" dur="0.3s" />
</polygon>
Loading States
<circle r="5">
<animate attributeName="r" values="5;8;5" dur="1s" repeatCount="indefinite" />
</circle>
Quick Reference
<!-- Circle to square -->
<rect rx="25"><animate attributeName="rx" to="0" /></rect>
<!-- Line to triangle -->
<polygon points="12 16, 20 16, 4 16">
<animate attributeName="points" to="12 4, 20 16, 4 16" />
</polygon>
<!-- Complex path morph -->
<path d="start-path">
<animate attributeName="d" to="end-path" />
</path>
Remember: You're not changing shapes, you're moving points!
Subscribe to my newsletter
Read articles from Tiger Abrodi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Tiger Abrodi
Tiger Abrodi
Just a guy who loves to write code and watch anime.