Arrow Button

Outline button that fills on hover while its arrow slides through.

Installation

  1. Install the dependencies

    $ npm i motion lucide-react
  2. Copy the source into components/ui/arrow-button.tsx

    components/ui/arrow-button.tsx
    "use client";
    
    import { ArrowRight } from "lucide-react";
    import type { ButtonHTMLAttributes } from "react";
    
    export function ArrowButton({ children, className = "", ...props }: ButtonHTMLAttributes<HTMLButtonElement>) {
      return (
        <button
          className={`group relative inline-flex items-center gap-3 overflow-hidden rounded-full border border-zinc-900 bg-white py-1.5 pl-5 pr-1.5 text-sm font-medium text-zinc-900 transition-colors duration-500 hover:text-white ${className}`}
          {...props}
        >
          <span
            aria-hidden
            className="absolute inset-0 origin-right scale-x-0 bg-zinc-900 transition-transform duration-500 ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:origin-left group-hover:scale-x-100"
          />
          <span className="relative">{children}</span>
          <span className="relative grid size-8 place-items-center overflow-hidden rounded-full bg-zinc-900 text-white transition-colors duration-500 group-hover:bg-white group-hover:text-zinc-900">
            <ArrowRight className="size-4 transition-transform duration-500 ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:translate-x-[180%]" />
            <ArrowRight className="absolute size-4 -translate-x-[180%] transition-transform duration-500 ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:translate-x-0" />
          </span>
        </button>
      );
    }
    
    export default function Demo() {
      return (
        <div className="flex flex-wrap items-center justify-center gap-4">
          <ArrowButton>Book a demo</ArrowButton>
          <ArrowButton className="border-blue-600 text-blue-600 [&>span:first-child]:bg-blue-600 [&>span:last-child]:bg-blue-600">
            View pricing
          </ArrowButton>
        </div>
      );
    }
    
  3. Use it

    The file exports the component and a Demo showing typical usage. Import whichever you need.