Liquid Metal Button
NewProA premium call-to-action whose body is flowing liquid metal: it surges toward the pointer, dimples and ripples when pressed, and can swell past its border.
- shader
- webgl
- button
- metal
- chrome
- cta
- hover
- ripple
Preset
Installation
Pro — coming soon
The source and installation instructions for this item ship with Kagadmodyaa Pro.
Usage
Use it like any other component. Choose a theme with preset; any prop you pass as well overrides the preset.
import { LiquidMetalButton } from '@/components/effects/liquid-metal-button/liquid-metal-button'
export function Hero() {
return (
<div className="flex items-center gap-4 p-6">
{/* the molten edge swells a few px past the border: give it room, and avoid overflow: hidden parents */}
<LiquidMetalButton preset="Gold" size="lg" iconEnd={<ArrowRight />} onClick={() => signUp()}>
Start for free
</LiquidMetalButton>
<LiquidMetalButton preset="Gunmetal" size="sm" label="Learn more" />
<LiquidMetalButton loading>Saving</LiquidMetalButton>
<LiquidMetalButton iconStart={<Plus />} aria-label="Add" />
</div>
)
}
// A normal <button>: type, disabled, ref, aria-* and every event prop work as usual.
// Presets: Chrome, Gold, Rose Gold, Gunmetal, Oil Slick. Any prop you pass (metalTint, roughness, studio...) overrides the preset.
// The stage above is <LiquidMetalButtonShowcase />, also exported, if you want the same hero composition.<LiquidMetalButton preset="Gold" size={"lg"} />Presets
ChromeGoldRose GoldGunmetalOil Slick
Props
| Name | Type | Default | Description |
|---|---|---|---|
| preset | 'Chrome' | 'Gold' | 'Rose Gold' | 'Gunmetal' | 'Oil Slick' | none (the defaults below) | A named theme. Any prop you pass as well overrides the preset’s value. |
| size | 'sm' | 'md' | 'lg' | 'lg' | Size of the button: sm 38px, md 48px, lg 62px tall. |
| label | 'Start for free' | 'Get early access' | 'Book a demo' | 'Continue' | 'Join the waitlist' | 'Start for free' | The label, when you do not pass children. Always real text, never part of the shader. |
| tone | 'auto' | 'dark' | 'light' | 'auto' | Which surface the button sits on. auto follows the page theme. |
| studio | 'chrome' | 'gold' | 'rose' | 'gunmetal' | 'oil' | 'chrome' | Which room the metal reflects: its sky, horizon, ground and light colours. Oil adds thin-film iridescence. |
| metalTint | string | '#eef2f8' | The colour of the mirror at normal incidence. A hex colour. |
| roughness | number | 0.1 | 0 is a mirror, 1 is satin: how soft the reflections are. Range 0 to 1. |
| intensity | number | 1 | Strength of the reflections and highlights. Range 0 to 1.5. |
| speed | number | 1 | How fast the metal flows at rest. 0 freezes it. Range 0 to 2. |
| surge | number | 1 | How hard the metal swells toward the pointer on hover. Range 0 to 2. |
| ripple | number | 1 | How strong the ripple rings are when you press. Range 0 to 2. |
| moltenEdge | boolean | true | Let the metal swell and drip a little past the border on hover, inside a small margin so layout never shifts. |
| className | string | — | Extra class on the root element. The effect fills its parent: give the parent a height. |
| style | CSSProperties | — | Inline style on the root element. |
Behaviour
- A real <button>: Enter and Space activate it, Tab focuses it, and a crisp focus-visible ring shows on keyboard focus. The label is ordinary text above the canvas, engraved into the metal with a text-shadow; the metal under it is calmed so it always reads.
- At rest the metal flows slowly. On hover it surges toward the pointer, brightens and a highlight follows the cursor; on press the surface dimples under your finger and a ripple ring expands from the press point, then it rebounds and settles (spring physics). Enter and Space ripple from the centre.
- Molten edge: on hover the metal swells and drips a few pixels past the border. It lives inside the button's own canvas margin so layout never shifts, but a parent with overflow: hidden will clip it. Turn it off for a clean pill.
- disabled dims it and freezes the metal; loading swirls the metal around a spinner, sets aria-busy and ignores clicks while keeping focus. Icons go in iconStart and iconEnd (decorative); a button with only an icon needs an aria-label.
- The canvas is created only while the button is near the viewport, and at most eight draw at once on a page. Beyond that a button keeps its CSS metal. It pauses off screen and in a background tab, lowers its resolution automatically if frames run slow, and draws one still frame under prefers-reduced-motion.
- Without WebGL, and before the first frame, you see a CSS metallic gradient in the same colours. Tone is 'auto' by default: it follows a dark or light class on <html> (or the OS setting) and re-reads it when the theme changes.