Icon Slide Button
A button with a sliding arrow icon that appears on hover with a smooth fill background transition
buttoniconslidehoveranimatedarrow
Preview
Source Code
"use client";
import { motion } from "framer-motion";
import { ArrowRight } from "lucide-react";
interface IconSlideButtonProps {
children?: React.ReactNode;
href?: string;
newTab?: boolean;
fontSize?: number;
borderRadius?: string;
bgColor?: string;
bgHoverColor?: string;
textColor?: string;
textHoverColor?: string;
fillColor?: string;
iconColor?: string;
iconHoverColor?: string;
className?: string;
onClick?: () => void;
}
const transition = {
duration: 0.4,
ease: [0.44, 0, 0.56, 1] as const,
};
export default function IconSlideButton({
children = "Get Started",
href,
newTab = false,
fontSize = 16,
borderRadius = "999px",
bgColor = "rgb(250, 250, 250)",
bgHoverColor = "rgb(8, 8, 8)",
textColor = "rgb(0, 0, 0)",
textHoverColor = "rgb(255, 255, 255)",
fillColor = "rgb(0, 0, 0)",
iconColor = "rgb(0, 0, 0)",
iconHoverColor = "rgb(255, 255, 255)",
className = "",
onClick,
}: IconSlideButtonProps) {
const Component = href ? motion.a : motion.button;
const linkProps = href
? { href, ...(newTab ? { target: "_blank", rel: "noopener noreferrer" } : {}) }
: {};
return (
<Component
{...linkProps}
onClick={onClick}
initial="idle"
whileHover="hover"
whileTap={{ scale: 0.97 }}
className={`icon-slide-btn ${className}`}
style={{
position: "relative",
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
overflow: "hidden",
border: "none",
cursor: "pointer",
textDecoration: "none",
borderRadius,
backgroundColor: bgColor,
}}
>
{/* Text */}
<motion.span
variants={{
idle: { color: textColor, paddingLeft: 24, paddingRight: 24 },
hover: { color: textHoverColor, paddingLeft: 20, paddingRight: 0 },
}}
transition={transition}
style={{
position: "relative",
zIndex: 2,
fontSize,
fontWeight: 500,
whiteSpace: "nowrap",
lineHeight: 1,
paddingTop: 15,
paddingBottom: 15,
}}
>
{children}
</motion.span>
{/* Arrow icon - slides in from right */}
<motion.span
variants={{
idle: { opacity: 0, width: 0, marginRight: 0 },
hover: { opacity: 1, width: fontSize + 4, marginRight: 20 },
}}
transition={transition}
style={{
position: "relative",
zIndex: 2,
display: "flex",
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
overflow: "hidden",
}}
>
<motion.span
variants={{
idle: { x: -12, color: iconColor },
hover: { x: 0, color: iconHoverColor },
}}
transition={transition}
style={{ display: "flex", alignItems: "center", flexShrink: 0 }}
>
<ArrowRight size={fontSize} strokeWidth={2} />
</motion.span>
</motion.span>
{/* Fill overlay - expands on hover */}
<motion.span
variants={{
idle: {
scale: 0,
opacity: 0,
},
hover: {
scale: 1,
opacity: 1,
},
}}
transition={transition}
style={{
position: "absolute",
inset: 0,
zIndex: 1,
borderRadius,
backgroundColor: fillColor,
transformOrigin: "center center",
}}
/>
</Component>
);
}