A button component with a magnetic pull effect that reacts to pointer movements.
Example
Installation
Copy and paste the source code into your project.
"use client";import*as React from"react";import { MotionValue, motion, useMotionValue, useTransform,} from"framer-motion";constmapRange= (inputLower:number,inputUpper:number,outputLower:number,outputUpper:number) => {constINPUT_RANGE= inputUpper - inputLower;constOUTPUT_RANGE= outputUpper - outputLower;return (value:number) => outputLower + (((value - inputLower) /INPUT_RANGE) *OUTPUT_RANGE||0);};constsetTransform= (item:HTMLElement&EventTarget,event:React.PointerEvent,x:MotionValue,y:MotionValue,rangeOffset:number) => {constbounds= item.getBoundingClientRect();constrelativeX= event.clientX - bounds.left;constrelativeY= event.clientY - bounds.top;constxRange=mapRange(0, bounds.width, -1, 1)(relativeX);constyRange=mapRange(0, bounds.height, -1, 1)(relativeY); x.set(xRange * rangeOffset); y.set(yRange * rangeOffset);};typeProps= {children?:React.ReactNode;rangeOffset?:number;fullWidth?:boolean;};/** * MagneticButton component. * * A button component with a magnetic pull effect that reacts to pointer movements. * * @param{React.ReactNode}[children] - The content of the button. * @param{number}[rangeOffset=30] - The range offset for the magnetic effect. * * @note The magnetic effect of the button relies on the button's `getBoundingClientRect` method. * This means that the effect is based on the button's dimensions and position within the viewport. * Be aware that changes in the button's size or its parent container may affect the magnetic effect's behavior. */exportconstMagneticButton= ({ children, rangeOffset =20, fullWidth =false,}:Props) => {constx=useMotionValue(0);consty=useMotionValue(0);constspanOffset=0.2;consttextX=useTransform(x, (latest) => latest * spanOffset);consttextY=useTransform(y, (latest) => latest * spanOffset);constcssVariables= { transitionProperty: "all", transitionDuration: "1000ms", transitionTimingFunction:"linear(0, 0.2178 2.1%, 1.1144 8.49%, 1.2959 10.7%, 1.3463 11.81%, 1.3705 12.94%, 1.3726, 1.3643 14.48%, 1.3151 16.2%, 1.0317 21.81%, 0.941 24.01%, 0.8912 25.91%, 0.8694 27.84%, 0.8698 29.21%, 0.8824 30.71%, 1.0122 38.33%, 1.0357, 1.046 42.71%, 1.0416 45.7%, 0.9961 53.26%, 0.9839 57.54%, 0.9853 60.71%, 1.0012 68.14%, 1.0056 72.24%, 0.9981 86.66%, 1)", } asReact.CSSProperties;return ( <motion.buttononPointerMove={(event) => {constitem= event.currentTarget;setTransform(item, event, x, y, rangeOffset); }}onPointerLeave={(_) => { x.set(0); y.set(0); }}whileTap={{ scale: 0.95 }}style={{ x, y,...cssVariables, }}className={`flex items-center justify-center ${fullWidth&&"w-full"}`} > <motion.divstyle={{ x: textX, y: textY, ...cssVariables }}className={`relative ${fullWidth&&"w-full"}`} > {children} </motion.div> </motion.button> );};
Update the import paths to match your project setup.
More Examples
Magnetic Button Socials
Props
Prop
Type
Default
Description
children
node
-
The content to be displayed inside the button. This is usually a text or an element.
rangeOffset
number
15
The intensity of the magnetic pull effect. A higher value increases the movement range of the button.
Notes
The magnetic effect of the button relies on the button's getBoundingClientRect method. This means that the effect is based on the button's dimensions and position within the viewport. Be aware that changes in the button's size or its parent container may affect the magnetic effect's behavior.