Start

Transaction

Work Email

Buttons

A collection of beautifully desgined buttons with fluid micro-interactions and svg animations that can be used for the beginning or the end of a frequent web action.

Gist

Completing a transaction, signing up, adding to cart, viewing links, etc. are tasks so mundane yet deeply personal to us. Actions so frequent, yet that mean so much to us. It is only fair they are acompained by beautifully crafted micro-interactions to express their true feelings, invisible behind these interactions.

Code

npm i framer-motion react-epic-spinners react-icons
/components/app/Buttons/button1.js
"use client"
import React, { useState } from "react"
import { motion } from "framer-motion"
const Button1 = () => {
const [ hover, setHover ] = useState(false)
const pathVariantsA = {
hidden: {
opacity:0,
pathLength:0
},
visible: {
opacity:1,
pathLength:1,
scale:[0.9,0.9,1,1.1,1.12,1.1,1],
transition:{
duration:0.7,
fade:0.7
}
}
}
const pathVariantsB = {
hidden: {
opacity:0,
pathLength:0
},
visible: {
opacity:1,
pathLength:1,
scale:[0.8,0.9,1,1.5,2,1.5,1],
rotate:[0,30,45,60,90,120,135,150,180,210,240,270,300,330,360],
transition:{
duration:2,
type:"spring",
stiffness:120,
bounce:1,
}
}
}
return (
<div>
<motion.div initial={{width:110}} whileHover={{width:135}} onHoverStart={() => setHover(true)} onHoverEnd={() => setHover(false)} transition={{duration:0.2,type:"spring",stiffness:120,bounce:0.2}} className="rounded-[15px] cursor-pointer mx-auto hover:bg-black hover:text-white flex gap-2 items-center justify-center border-solid border-[2px] border-[#000000] px-4 h-[35px]">
{hover &&
<motion.svg width="18px" height="18px" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff">
<motion.path variants={pathVariantsA} initial="hidden" animate={hover ? "visible" : "hidden"} d="M21 13v3a4 4 0 01-4 4H7a4 4 0 01-4-4v-2.4a.6.6 0 01.6-.6H21zM16 20l1 2M8 20l-1 2M21 13V7a4 4 0 00-4-4h-5" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></motion.path>
<motion.path variants={pathVariantsB} initial="hidden" animate={hover ? "visible" : "hidden"} d="M15.4 8H8.6c-.331 0-.596-.268-.56-.598C8.186 6.075 8.863 3 12 3s3.814 3.075 3.96 4.402c.036.33-.229.598-.56.598z" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></motion.path>
</motion.svg>}
{!hover &&
<svg width="18px" height="18px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000">
<path d="M6.906 4.537A.6.6 0 006 5.053v13.894a.6.6 0 00.906.516l11.723-6.947a.6.6 0 000-1.032L6.906 4.537z" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>}
<p className="[font-family:'Calming'] text-[17px]">Start</p>
</motion.div>
</div>
)
}
export default Button1
/components/app/Buttons/button2.js
"use client"
import React, { useState } from "react"
import { motion } from "framer-motion"
import { HollowDotsSpinner } from 'react-epic-spinners'
const Button2 = () => {
const [hover, setHover] = useState(false)
const [isDone, setIsDone] = useState(false)
const [ width, setWidth ] = useState(150)
{hover && setTimeout(() => {
// Can add any function here
// Run these after function runs/returns data successfully
// Button will be 'loading' untill then
setHover(false)
setIsDone(true)
setWidth(140)
}, 2000)}
const pathVariantsA = {
hidden: {
opacity:0,
pathLength:0
},
visible: {
opacity:1,
pathLength:1,
scale:[0.9,0.9,1,1.1,1.16,1.1,1],
transition:{
duration:0.7,
fade:0.7
}
}
}
return (
<div>
{/* Color Time */}
<motion.div initial={{width:150}} animate={{width:width,backgroundColor:isDone ? "#00ff00" : "black"}} onTap={() => {setHover(true)
setIsDone(false)
setWidth(80)}} transition={{duration:0.2,type:"spring",stiffness:120,bounce:0.4}} className="rounded-[15px] w-fit break-keep bg-black overflow-hidden cursor-pointer text-center flex gap-2 text-white mx-auto items-center justify-center px-4 h-[35px]">
{hover && <HollowDotsSpinner color="white" size={7} className='absolute'/>}
{isDone && <svg width="20px" height="20px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff"><motion.path variants={pathVariantsA} initial="hidden" animate={isDone ? "visible" : "hidden"} d="M7 12.5l3 3 7-7" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></motion.path><motion.path variants={pathVariantsA} initial="hidden" animate={isDone ? "visible" : "hidden"} d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></motion.path></svg>}
{!isDone && <svg width="20px" height="20px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff"><path d="M18 22a3 3 0 100-6 3 3 0 000 6zM18 8a3 3 0 100-6 3 3 0 000 6zM6 15a3 3 0 100-6 3 3 0 000 6z" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M15.5 6.5l-7 4M8.5 13.5l7 4" stroke="#ffffff" stroke-width="1.5"></path></svg>}
<motion.p animate={{x:hover ? 200 : 0}} onAnimationComplete={() => {isDone ? setTimeout(() => {setIsDone(false)
setHover(false)
setWidth(150)}, 3000) : null}} transition={{duration:0.3}} className="[font-family:'Maglite'] break-keep w-fit text-[17px] h-[20px]">{isDone ? "Secure" : "Transaction"}</motion.p>
</motion.div>
</div>
)
}
export default Button2
/components/app/Buttons/button3.js
"use client"
import React, { useState } from "react"
import { motion } from "framer-motion"
import {HiOutlineArrowUpRight} from "react-icons/hi2"
const Button3 = () => {
const [hover, setHover] = useState(false)
const [isDone, setIsDone] = useState(false)
return (
<div>
<motion.div onHoverStart={() => setHover(true)} onHoverEnd={() => setHover(false)} className="h-[35px] mx-auto relative hover:bg-white hover:text-black hover:duration-700 cursor-default w-[200px] break-keep p-3 overflow-hidden rounded-2xl text-white gap-3 text-center flex items-center">
<div class="relative flex h-3 w-3">
<div class="animate-ping absolute inline-flex h-full w-full rounded-full bg-pink-400 opacity-75"></div>
<div class="relative inline-flex rounded-full h-3 w-3 bg-pink-500"></div>
</div>
<motion.p animate={{ y: hover ? -50 : 0}} className="[font-family:'Calming']">Work Email</motion.p>
{hover && <motion.p initial={{ y: 50}} animate={{ y: 0 }} className="[font-family:'Calming'] absolute ml-7 flex gap-1 break-keep items-center">rob@gmail.com <HiOutlineArrowUpRight size={15} /></motion.p>}
</motion.div>
</div>
)
}
export default Button3

The code for this component is here. Some libraries used are:

  • Next.js
  • framer-motion
  • tailwindcss
  • react-epic-spinners
  • react-icons