SVG animation
Motion makes React SVG animation straightforward. In this guide, we'll learn how to make line drawing animations, path morphing animations, animate viewBox and more.
Overview
SVG animations are generally performed as usual, via the motion component. There's a motion component for every SVG element (e.g. <motion.svg>, <motion.path>, <motion.circle>, and even filters like <motion.feTurbulence> and <motion.feDisplacementMap>).
<motion.svg> <motion.circle /> </motion.svg>
A motion component can animate style, as normal:
<motion.circle style={{ fill: "#00f" }} animate={{ fill: "#f00" }} />
But it can also animate attributes:
<motion.circle cx={0} animate={{ cx: 50 }} />
Animate viewBox
The motion.svg component can additionally animate viewBox. This is especially useful for easy panning animations:
<motion.svg viewBox="0 0 200 200" animate={{ viewBox: "100 0 200 200" }} // 100px to the right />
Or zoom in/out animations:
<motion.svg viewBox="0 0 200 200" animate={{ viewBox: "-100 -100 300 300" }} // Zoom out />
Transforms
SVG transforms work differently to CSS transforms. When we define a CSS transform, the default origin is relative to the element itself. So for instance, this div will rotate around its center point, as you'd intuitively expect:
<motion.div style={{ rotate: 90 }} />
With SVGs, the transform point is relative to the top/left corner of the viewBox, which is less intuitive. Motion changes this behaviour so SVGs work the same as normal elements. Therefore, this:
<motion.rect style={{ rotate: 90 }} />
Will also rotate the rect element around its center point.
The default behaviour can be restored by explicitly setting an element's transformBox style:
<motion.rect style={{ rotate: 90, transformBox: "view-box" }} />
x/y/scale attributes
motion components provide shorthands for x, y, and scale transforms:
<motion.div animate={{ x: 100 }} />
With SVG components, these will still render via the style tag. This is usually fine, but some SVG components accept x, y, and scale attributes also. You can target these via animation props using attrX, attrY and attrScale respectively:
<motion.rect attrX={0} animate={{ attrX: 100 }} />
Passing MotionValue
Motion values should be passed via style, when animating regular styles, or via the component's attribute where appropriate:
const cx = useMotionValue(100) const opacity = useMotionValue(1) return <motion.rect cx={cx} style={{ opacity }} />
Line drawing
Motion simplifies the creation of “hand-drawn” line animations using three special values. Each is set as a 0-1 progress value, where 1 is the total length of the line:
pathLength: total drawn lengthpathSpacing: length between segmentspathOffset: where the segment starts
These values work on path, circle, ellipse, line, polygon, polyline, rect.
<motion.path d={d} initial={{ pathLength: 0 }} animate={{ pathLength: 1 }} />
Path morphing
It's possible to also animate the shape of a path via its d attribute.
<motion.path d="M 0,0 l 0,10 l 10,10" animate={{ d: "M 0,0 l 10,0 l 10,10" }} />
This works natively in Motion as long as the two paths are similar. You can see in the example above that each path has the same number and type of path instructions.
For interpolating between very different paths, you can incorporate a third-party path mixer like Flubber:
Motion makes React SVG animation straightforward. In this guide, we'll learn how to make line drawing animations, path morphing animations, animate viewBox and more.
Overview
SVG animations are generally performed as usual, via the motion component. There's a motion component for every SVG element (e.g. <motion.svg>, <motion.path>, <motion.circle>, and even filters like <motion.feTurbulence> and <motion.feDisplacementMap>).
<motion.svg> <motion.circle /> </motion.svg>
A motion component can animate style, as normal:
<motion.circle style={{ fill: "#00f" }} animate={{ fill: "#f00" }} />
But it can also animate attributes:
<motion.circle cx={0} animate={{ cx: 50 }} />
Animate viewBox
The motion.svg component can additionally animate viewBox. This is especially useful for easy panning animations:
<motion.svg viewBox="0 0 200 200" animate={{ viewBox: "100 0 200 200" }} // 100px to the right />
Or zoom in/out animations:
<motion.svg viewBox="0 0 200 200" animate={{ viewBox: "-100 -100 300 300" }} // Zoom out />
Transforms
SVG transforms work differently to CSS transforms. When we define a CSS transform, the default origin is relative to the element itself. So for instance, this div will rotate around its center point, as you'd intuitively expect:
<motion.div style={{ rotate: 90 }} />
With SVGs, the transform point is relative to the top/left corner of the viewBox, which is less intuitive. Motion changes this behaviour so SVGs work the same as normal elements. Therefore, this:
<motion.rect style={{ rotate: 90 }} />
Will also rotate the rect element around its center point.
The default behaviour can be restored by explicitly setting an element's transformBox style:
<motion.rect style={{ rotate: 90, transformBox: "view-box" }} />
x/y/scale attributes
motion components provide shorthands for x, y, and scale transforms:
<motion.div animate={{ x: 100 }} />
With SVG components, these will still render via the style tag. This is usually fine, but some SVG components accept x, y, and scale attributes also. You can target these via animation props using attrX, attrY and attrScale respectively:
<motion.rect attrX={0} animate={{ attrX: 100 }} />
Passing MotionValue
Motion values should be passed via style, when animating regular styles, or via the component's attribute where appropriate:
const cx = useMotionValue(100) const opacity = useMotionValue(1) return <motion.rect cx={cx} style={{ opacity }} />
Line drawing
Motion simplifies the creation of “hand-drawn” line animations using three special values. Each is set as a 0-1 progress value, where 1 is the total length of the line:
pathLength: total drawn lengthpathSpacing: length between segmentspathOffset: where the segment starts
These values work on path, circle, ellipse, line, polygon, polyline, rect.
<motion.path d={d} initial={{ pathLength: 0 }} animate={{ pathLength: 1 }} />
Path morphing
It's possible to also animate the shape of a path via its d attribute.
<motion.path d="M 0,0 l 0,10 l 10,10" animate={{ d: "M 0,0 l 10,0 l 10,10" }} />
This works natively in Motion as long as the two paths are similar. You can see in the example above that each path has the same number and type of path instructions.
For interpolating between very different paths, you can incorporate a third-party path mixer like Flubber:
Motion makes React SVG animation straightforward. In this guide, we'll learn how to make line drawing animations, path morphing animations, animate viewBox and more.
Overview
SVG animations are generally performed as usual, via the motion component. There's a motion component for every SVG element (e.g. <motion.svg>, <motion.path>, <motion.circle>, and even filters like <motion.feTurbulence> and <motion.feDisplacementMap>).
<motion.svg> <motion.circle /> </motion.svg>
A motion component can animate style, as normal:
<motion.circle style={{ fill: "#00f" }} animate={{ fill: "#f00" }} />
But it can also animate attributes:
<motion.circle cx={0} animate={{ cx: 50 }} />
Animate viewBox
The motion.svg component can additionally animate viewBox. This is especially useful for easy panning animations:
<motion.svg viewBox="0 0 200 200" animate={{ viewBox: "100 0 200 200" }} // 100px to the right />
Or zoom in/out animations:
<motion.svg viewBox="0 0 200 200" animate={{ viewBox: "-100 -100 300 300" }} // Zoom out />
Transforms
SVG transforms work differently to CSS transforms. When we define a CSS transform, the default origin is relative to the element itself. So for instance, this div will rotate around its center point, as you'd intuitively expect:
<motion.div style={{ rotate: 90 }} />
With SVGs, the transform point is relative to the top/left corner of the viewBox, which is less intuitive. Motion changes this behaviour so SVGs work the same as normal elements. Therefore, this:
<motion.rect style={{ rotate: 90 }} />
Will also rotate the rect element around its center point.
The default behaviour can be restored by explicitly setting an element's transformBox style:
<motion.rect style={{ rotate: 90, transformBox: "view-box" }} />
x/y/scale attributes
motion components provide shorthands for x, y, and scale transforms:
<motion.div animate={{ x: 100 }} />
With SVG components, these will still render via the style tag. This is usually fine, but some SVG components accept x, y, and scale attributes also. You can target these via animation props using attrX, attrY and attrScale respectively:
<motion.rect attrX={0} animate={{ attrX: 100 }} />
Passing MotionValue
Motion values should be passed via style, when animating regular styles, or via the component's attribute where appropriate:
const cx = useMotionValue(100) const opacity = useMotionValue(1) return <motion.rect cx={cx} style={{ opacity }} />
Line drawing
Motion simplifies the creation of “hand-drawn” line animations using three special values. Each is set as a 0-1 progress value, where 1 is the total length of the line:
pathLength: total drawn lengthpathSpacing: length between segmentspathOffset: where the segment starts
These values work on path, circle, ellipse, line, polygon, polyline, rect.
<motion.path d={d} initial={{ pathLength: 0 }} animate={{ pathLength: 1 }} />
Path morphing
It's possible to also animate the shape of a path via its d attribute.
<motion.path d="M 0,0 l 0,10 l 10,10" animate={{ d: "M 0,0 l 10,0 l 10,10" }} />
This works natively in Motion as long as the two paths are similar. You can see in the example above that each path has the same number and type of path instructions.
For interpolating between very different paths, you can incorporate a third-party path mixer like Flubber:

