🏹 Expandable Icon Button
Think of this as the Clark Kent of buttons—small, subtle, and all business at first. But the moment you hover, BOOM! 💥 It expands, revealing its secret identity (a text label!). Perfect for minimalist UIs, modern dashboards, or interactive call-to-actions, this button keeps things sleek while adding a touch of surprise and delight.
Preview
Follow below steps 👇🏻
Install dependencies
1npm i framer-motion
Component
Create a file expandable-icon-button.tsx in your components folder and paste this code
1'use client';23import { motion, useAnimationControls } from 'framer-motion';4import { MouseEventHandler, useEffect, useRef, useState } from 'react';56type ExpandableIconButtonProps = {7onClick?: MouseEventHandler<HTMLButtonElement>;8icon: React.ReactNode;9text: string;10className?: string;11};1213const ExpandableIconButton = ({ onClick, icon, text, className }: ExpandableIconButtonProps) => {14const buttonControls = useAnimationControls();15const textControls = useAnimationControls();1617const textRef = useRef<HTMLParagraphElement>(null);18const [textWidth, setTextWidth] = useState<number>(0);19const iconRef = useRef<HTMLDivElement>(null);20const [iconWidth, setIconWidth] = useState<number>(0);2122useEffect(() => {23if (iconRef.current) {24setIconWidth(iconRef.current.offsetWidth);25}26if (textRef.current) {27setTextWidth(textRef.current.offsetWidth);28}29}, [iconRef, textRef]);3031const onMouseEnter = () => {32buttonControls.start({ width: iconWidth + textWidth + 40 });33textControls.start('visible');34};3536const onMouseLeave = () => {37buttonControls.start({ width: iconWidth + 32 });38textControls.start('hide');39};4041return (42<motion.button43onClick={onClick}44animate={buttonControls}45transition={{ duration: 0.4, ease: 'backOut' }}46onMouseEnter={onMouseEnter}47onMouseLeave={onMouseLeave}48style={{49gridTemplateColumns: 'auto 1fr',50width: iconWidth + 32,51opacity: iconWidth <= 0 ? 0 : 152}}53className={`grid grid-cols-2 items-center p-[16px] justify-start gap-[8px] rounded-full overflow-hidden ${className}`}54>55<div ref={iconRef} className="p-0 flex items-center justify-center">56{icon}57</div>58<motion.p59ref={textRef}60initial={{ opacity: 0, scale: 0 }}61variants={{62visible: { opacity: 1, scale: 1 },63hide: { opacity: 0, scale: 0 }64}}65animate={textControls}66>67{text}68</motion.p>69</motion.button>70);71};7273export default ExpandableIconButton;
Usage
1<ExpandableIconButton2onClick={() => (window.location.href = 'https://twitter.com/samitkapoorr')}3icon={<TwitterIcon />}4text={'samitkapoorr'}5className="border-[1px] hover:bg-blue-500"6/>
⭐️ Got a question or feedback?
Feel free to reach out!