DocumentationAnimated Button

Animated Button

A button with a shiny border and text reveal effect, perfect for calls to action.

Install using CLI

npx shadcn@latest add "https://vengeance-ui.vercel.app/r/animated-button.json"

Install Manually

1

Install dependencies

npm install framer-motion clsx tailwind-merge
2

Add util file

lib/utils.ts

import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
3

Copy the source code

Copy the code below and paste it into components/ui/animated-button.tsx

'use client'
import React from 'react'
import { motion, type MotionProps } from 'framer-motion'
import { cn } from '@/lib/utils'
type AnimatedButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & MotionProps & {
children?: React.ReactNode
}
const AnimatedButton: React.FC<AnimatedButtonProps & { as?: any }> = ({
children = 'Browse Components',
className = '',
as = 'button',
whileTap = { scale: 0.97 },
transition = {
stiffness: 20,
damping: 15,
mass: 2,
scale: {
type: 'spring',
stiffness: 10,
damping: 5,
mass: 0.1,
},
},
...rest
}) => {
const Component = (motion as any)[as] || motion.button
return (
<Component
{...rest}
whileTap={whileTap}
transition={transition}
className={cn(
'px-6 py-2 rounded-md relative overflow-hidden bg-neutral-50 dark:bg-black border border-neutral-300 dark:border-neutral-800',
'text-neutral-900 dark:text-neutral-100 [--shine:rgba(0,0,0,.66)] dark:[--shine:rgba(255,255,255,.66)]',
className
)}
>
<motion.span
className="tracking-wide font-light h-full w-full flex items-center justify-center relative z-10"
style={{
WebkitMaskImage:
'linear-gradient(-75deg, white calc(var(--mask-x) + 20%), transparent calc(var(--mask-x) + 30%), white calc(var(--mask-x) + 100%))',
maskImage:
'linear-gradient(-75deg, white calc(var(--mask-x) + 20%), transparent calc(var(--mask-x) + 30%), white calc(var(--mask-x) + 100%))',
}}
initial={{ ['--mask-x']: '100%' } as any}
animate={{ ['--mask-x']: '-100%' } as any}
transition={{ repeat: Infinity, duration: 1, ease: 'linear', repeatDelay: 1 }}
>
{children}
</motion.span>
<motion.span
className="block absolute inset-0 rounded-md p-px"
style={{
background: 'linear-gradient(-75deg, transparent 30%, var(--shine) 50%, transparent 70%)',
backgroundSize: '200% 100%',
mask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
maskComposite: 'exclude',
WebkitMask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
WebkitMaskComposite: 'xor',
}}
initial={{ backgroundPosition: '100% 0', opacity: 0 }}
animate={{ backgroundPosition: ['100% 0', '0% 0'], opacity: [0, 1, 0] }}
transition={{ duration: 1, repeat: Infinity, ease: 'linear', repeatDelay: 1 }}
/>
</Component>
)
}
export default AnimatedButton

Usage

1import AnimatedButton from "@/components/ui/animated-button"
2
3export function AnimatedButtonDemo() {
4return (
5 <AnimatedButton>
6 Get Started
7 </AnimatedButton>
8)
9}

Props

Prop NameTypeDefaultDescription
childrenReact.ReactNode'Browse Components'The content to be displayed inside the button.
classNamestring''Additional CSS classes to apply to the button.
whileTapTargetAndTransition{ scale: 0.97 }Framer Motion animation properties for the tap (click) state.
transitionTransition{ ...spring }Framer Motion transition configuration.