Interactive Demo
Copy the code below into a new file, e.g., components/ui/glassy-button.tsx. It requires the cn utility from lib/utils.
1import { cn } from "@/lib/utils";2import React from "react";34interface GlassyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {5 children?: React.ReactNode;6 className?: string;7 dark?: boolean;8 onClick?: () => void;9 square?: boolean;10 // presets11 size?: "xs" | "sm" | "md" | "lg";12 disabled?: boolean;1314};1516export default function GlassyButton({17 children = "",18 className,19 onClick,20 square = false,21 dark = false,22 size = "md",23 disabled = false2425}: GlassyButtonProps) {26 const sizes = {27 xs: `h-4 px-2 text-[7px] ${square && 'w-4'}`,28 sm: `h-9 px-4 text-xs ${square && 'w-9'} `,29 md: `h-12 px-6 text-sm ${square && 'w-12'}`,30 lg: `h-14 px-8 text-base ${square && 'w-14'} `,31 };3233 return (34 <button35 onClick={onClick}36 disabled={disabled}37 className={cn(38 "relative inline-flex items-center justify-center rounded-full select-none cursor-pointer hover:scale-105 transition-all",39 "backdrop-blur-[4px]",40 "transition duration-500 active:scale-120",4142 // shadows43 "shadow-[inset_-2px_-1px_1px_-2px_rgba(255,255,255,1)]",44 "before:content-[''] before:absolute before:inset-0 before:rounded-full",45 "before:shadow-[inset_2px_1px_1px_-2px_rgba(255,255,255,1)]",46 "after:content-[''] after:absolute after:inset-0 after:rounded-full",47 "after:shadow-[inset_2px_1px_2px_-2px_rgba(255,255,255,1)]",4849 dark ?50 "bg-black/10 hover:bg-black/20 active:bg-black/30" :51 "bg-white/10 hover:bg-white/20 active:bg-white/30",5253 disabled && "opacity-50 cursor-not-allowed ",54 // fallback size55 sizes[size],56 className57 )}5859 >60 {/* inner glass layer */}61 <span62 className="absolute inset-0 rounded-full shadow-[inset_-2px_-1px_2px_-2px_rgba(255,255,255,1)]"63 aria-hidden64 />6566 {/* content */}67 <span className="relative z-10 font-medium text-nowrap">68 {children}69 </span>70 </button>71 );72}