Motion Toggle
A smooth toggle switch with a squish animation effect.
Tags: Buttons, Toggle
React Code
"use client";
import React, { useState } from "react";
import { motion } from "framer-motion";
const pathOff =
"M26 14C26 20.6274 20.6274 26 14 26C7.3726 26 2 20.6274 2 14C2 7.3726 7.3726 2 14 2C20.6274 2 26 7.3726 26 14Z";
const pathStretchRight =
"M39 14C39 20.6274 26.6274 26 20 26C13.3726 26 8 20.6274 8 14C8 7.37258 13.3726 2 20 2C26.6274 2 39 7.37258 39 14Z";
const pathOn =
"M56 14C56 20.6274 50.6274 26 44 26C37.3726 26 32 20.6274 32 14C32 7.3726 37.3726 2 44 2C50.6274 2 56 7.3726 56 14Z";
const pathStretchLeft =
"M50 14C50 20.6274 44.6274 26 38 26C31.3726 26 20.5 20.6274 20.5 14C20.5 7.37258 31.3726 2 38 2C44.6274 2 50 7.37258 50 14Z";
export function MotionToggle() {
const [isOn, setIsOn] = useState(false);
return (
<motion.button
onClick={() => setIsOn(!isOn)}
initial={false}
animate={{
backgroundColor: isOn ? "#1F2123" : "#FFFFFF",
borderColor: isOn ? "#1F2123" : "#DEE1E4",
}}
className="relative flex h-[30px] w-[60px] cursor-pointer items-center justify-center rounded-full border shadow-sm"
transition={{ duration: 0.4, ease: "easeInOut" }}
>
<svg
width="58"
height="28"
viewBox="0 0 58 28"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="absolute inset-0 m-auto"
>
<motion.path
initial={false}
animate={
isOn
? {
d: [pathOff, pathStretchRight, pathOn],
fill: "#FFFFFF",
}
: {
d: [pathOn, pathStretchLeft, pathOff],
fill: "#1F2123",
}
}
transition={{
duration: 0.4,
ease: "easeInOut",
times: [0, 0.5, 1],
}}
/>
</svg>
</motion.button>
);
}