Some Examples » 20. SVG path length

20. SVG path length

Most of these examples use motion.divs, but you can animate any HTML or SVG element with Framer Motion; there are even a few extra properties for SVG paths.

Code component

This is primarily a simple animate-driven animation, toggled by the isChecked state.

When isChecked is false:

  • The motion.div will have a scale of 0.8 and a 50% transparent white backgroundColor,
  • and the pathLength of the motion.path will be 0.

When isChecked is true:

  • The motion.div will have a scale of 1, and its backgroundColor becomes fully opaque,
  • and the pathLength of the motion.path will be 0.9.
export function CC_20_SVG_path_length(props) {
    const [isChecked, setIsChecked] = useState(true)
    const pathLength = useMotionValue(0)
    const opacity = useTransform(pathLength, [0.05, 0.15], [0, 1])

    return (
        <div>
            <motion.div
                animate={{
                    scale: isChecked ? 1 : 0.8,
                    backgroundColor: isChecked
                        ? "rgba(255, 255, 255, 1)"
                        : "rgba(255, 255, 255, 0.5)",
                }}
                transition={{ type: "spring", stiffness: 300, damping: 20 }}
                onTap={() => setIsChecked(!isChecked)}
            >
                <svg>
                    <motion.path
                        d="M38 74.707l24.647 24.646L116.5 45.5"
                        fill="transparent"
                        strokeWidth="20"
                        stroke="#39e"
                        strokeLinecap="round"
                        initial={{ pathLength: 0.9, opacity: 1 }}
                        animate={{ pathLength: isChecked ? 0.9 : 0 }}
                        style={{ pathLength, opacity }}
                    />
                </svg>
            </motion.div>
        </div>
    )
}

But we’re also hooking into the pathLength animation to change the motion.path’s opacity.

A pathLength Motion value is passed to the path’s pathLength property, and a useTransform() is used to change the path’s opacity at the very beginning of the pathLength animation: The checkmark quickly fades in when pathLength changes from 0.05 to 0.15.

export function CC_20_SVG_path_length(props) {
    const [isChecked, setIsChecked] = useState(true)
    const pathLength = useMotionValue(0)
    const opacity = useTransform(pathLength, [0.05, 0.15], [0, 1])

    return (
        <div>
            <motion.div
                animate={{
                    scale: isChecked ? 1 : 0.8,
                    backgroundColor: isChecked
                        ? "rgba(255, 255, 255, 1)"
                        : "rgba(255, 255, 255, 0.5)",
                }}
                transition={{ type: "spring", stiffness: 300, damping: 20 }}
                onTap={() => setIsChecked(!isChecked)}
            >
                <svg>
                    <motion.path
                        d="M38 74.707l24.647 24.646L116.5 45.5"
                        fill="transparent"
                        strokeWidth="20"
                        stroke="#39e"
                        strokeLinecap="round"
                        initial={{ pathLength: 0.9, opacity: 1 }}
                        animate={{ pathLength: isChecked ? 0.9 : 0 }}
                        style={{ pathLength, opacity }}
                    />
                </svg>
            </motion.div>
        </div>
    )
}

It’s hardly noticeable, but you can uncomment the transition line inside the motion.path to see a three-second-long version of the animation.

Code override

A Graphic on the canvas is also (technically) an SVG, but you can’t attach an override to it. So, how do you animate an SVG with code overrides? By inserting the SVG as the override’s children:

export function SVG_path_length(Component): ComponentType {
    return (props) => {
        const [isChecked, setIsChecked] = useState(true)
        const pathLength = useMotionValue(0)
        const opacity = useTransform(pathLength, [0.05, 0.15], [0, 1])

        return (
            <Component
                {...props}
                animate={{
                    scale: isChecked ? 1 : 0.8,
                    backgroundColor: isChecked
                        ? "rgba(255, 255, 255, 1)"
                        : "rgba(255, 255, 255, 0.5)",
                }}
                transition={{ type: "spring", stiffness: 300, damping: 20 }}
                onTap={() => setIsChecked(!isChecked)}
                children={
                    <svg
                        xmlns="http://www.w3.org/2000/svg"
                        width="150"
                        height="150"
                    >
                        <motion.path
                            d="M38 74.707l24.647 24.646L116.5 45.5"
                            fill="transparent"
                            strokeWidth="20"
                            stroke="#39e"
                            strokeLinecap="round"
                            animate={{ pathLength: isChecked ? 0.9 : 0 }}
                            style={{ pathLength: pathLength, opacity: opacity }}
                        />
                    </svg>
                }
            />
        )
    }
}

Other examples of using children in a code override:


Join the Mighty Guides mailing list    ( ± 6 emails/year )

GDPR

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing per their Privacy Policy and Terms.



Leave a Reply