docsLiquid Metal

Liquid Metal

A premium button component with a mesmerizing liquid chrome border effect using WebGL shaders. Perfect for CTAs and hero sections.

Loading Preview...

Install using CLI

npx shadcn@latest add "https://www.vengenceui.com/r/liquid-metal.json"

Install Manually

1

Install dependencies

npm install @paper-design/shaders-react 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/liquid-metal.tsx

"use client";
import React, { memo, forwardRef } from "react";
import { LiquidMetal as LiquidMetalShader } from "@paper-design/shaders-react";
import { cn } from "@/lib/utils";
export interface LiquidMetalProps {
colorBack?: string;
colorTint?: string;
speed?: number;
repetition?: number;
distortion?: number;
scale?: number;
className?: string;
style?: React.CSSProperties;
}
export const LiquidMetal = memo(function LiquidMetal({
colorBack = "#aaaaac",
colorTint = "#ffffff",
speed = 0.5,
repetition = 4,
distortion = 0.1,
scale = 1,
className,
style,
}: LiquidMetalProps) {
return (
<div className={cn("absolute inset-0 z-0 overflow-hidden", className)} style={style}>
<LiquidMetalShader
colorBack={colorBack}
colorTint={colorTint}
speed={speed}
repetition={repetition}
distortion={distortion}
softness={0}
shiftRed={0.3}
shiftBlue={-0.3}
angle={45}
shape="none"
scale={scale}
fit="cover"
style={{ width: "100%", height: "100%" }}
/>
</div>
);
});
LiquidMetal.displayName = "LiquidMetal";
export interface LiquidMetalButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
children: React.ReactNode;
icon?: React.ReactNode;
borderWidth?: number;
metalConfig?: Omit<LiquidMetalProps, "className" | "style">;
size?: "sm" | "md" | "lg";
}
export const LiquidMetalButton = forwardRef<HTMLButtonElement, LiquidMetalButtonProps>(
({ children, icon, borderWidth = 4, metalConfig, size = "md", className, disabled, ...props }, ref) => {
const sizeStyles = {
sm: "py-2 pl-2 pr-6 gap-3 text-sm",
md: "py-3 pl-3 pr-8 gap-4 text-base",
lg: "py-4 pl-4 pr-10 gap-6 text-lg",
};
const iconSizes = { sm: "w-8 h-8", md: "w-10 h-10", lg: "w-12 h-12" };
return (
<button
ref={ref}
disabled={disabled}
className={cn(
"relative group cursor-pointer border-none bg-transparent p-0 outline-none transition-transform active:scale-[0.98] disabled:opacity-50 disabled:cursor-not-allowed",
className
)}
{...props}
>
<div className="relative rounded-full overflow-hidden shadow-[0_20px_50px_-12px_rgba(0,0,0,0.25)]" style={{ padding: borderWidth }}>
<LiquidMetal
colorBack={metalConfig?.colorBack ?? "#888888"}
colorTint={metalConfig?.colorTint ?? "#ffffff"}
speed={metalConfig?.speed ?? 0.4}
repetition={metalConfig?.repetition ?? 4}
distortion={metalConfig?.distortion ?? 0.15}
scale={metalConfig?.scale ?? 1}
className="absolute inset-0 z-0 rounded-full"
/>
<div className={cn(
"relative z-10 rounded-full flex items-center bg-white dark:bg-black transition-colors group-hover:bg-neutral-50 dark:group-hover:bg-neutral-900",
sizeStyles[size]
)}>
{icon && (
<div className={cn("rounded-full flex items-center justify-center bg-neutral-100 dark:bg-neutral-800 shadow-[inset_0_2px_4px_rgba(0,0,0,0.06)]", iconSizes[size])}>
<span className="text-neutral-700 dark:text-neutral-300">{icon}</span>
</div>
)}
<span className="font-medium tracking-tight text-neutral-900 dark:text-white">{children}</span>
</div>
</div>
</button>
);
}
);
LiquidMetalButton.displayName = "LiquidMetalButton";
export default LiquidMetalButton;

Usage

1import { LiquidMetalButton } from "@/components/ui/liquid-metal"
2import { ArrowRight } from "lucide-react"
3
4export function LiquidMetalDemo() {
5return (
6 <LiquidMetalButton
7 icon={<ArrowRight className="w-5 h-5" />}
8 metalConfig={{
9 colorBack: "#3b82f6",
10 colorTint: "#93c5fd",
11 }}
12 >
13 Click Me
14 </LiquidMetalButton>
15)
16}

Color Themes

All available color themes in one view: Chrome, Blue, Gold, Prism, and Emerald.

Loading Preview...

Props

LiquidMetalButton

Prop NameTypeDefaultDescription
childrenReact.ReactNode-The button text/content.
iconReact.ReactNode-Optional icon displayed on the left side of the button.
size'sm' | 'md' | 'lg''md'Size variant of the button.
borderWidthnumber4Width of the liquid metal border in pixels.
metalConfigLiquidMetalProps-Configuration object for the liquid metal shader effect.
classNamestring-Additional CSS classes for the button container.
disabledbooleanfalseWhether the button is disabled.

metalConfig (LiquidMetalProps)

Prop NameTypeDefaultDescription
colorBackstring'#888888'Base background color of the liquid metal effect.
colorTintstring'#ffffff'Tint/highlight color for the chrome reflections.
speednumber0.4Animation speed of the fluid movement (0.1 - 2.0 recommended).
repetitionnumber4Pattern complexity (1 - 10).
distortionnumber0.15Wave distortion amount (0 - 1).
scalenumber1Scale of the effect texture.

Credits

This component was created by Anshu.