07 / 30
All 30 in 30 Tailwind CSS Hover Effects
- 01Tailwind Underline Draw Hover Effect
- 02Tailwind Text Glitch Hover Effect
- 03Tailwind Letter Spacing Expand Hover Effect
- 04Tailwind Gradient Text Reveal Hover Effect
- 05Tailwind Split Text Hover Effect
- 06Tailwind Neon Glow Text Hover Effect
- 07Tailwind Magnetic Liquid Button Hover Effect
- 08Tailwind Border Draw Hover Effect
- 09Tailwind Shimmer Shine Button Hover Effect
- 10Tailwind Fill Wipe Button Hover Effect
- 11Tailwind 3D Press Button Hover Effect
- 12Tailwind Ripple Button Hover Effect
- 13Tailwind 3D Tilt Card Hover Effect
- 14Tailwind Card Flip Hover Effect
- 15Tailwind Glassmorphism Card Hover Effect
- 16Tailwind Spotlight Card Hover Effect
- 17Tailwind Slide Reveal Card Hover Effect
- 18Tailwind Stack Lift Card Hover Effect
- 19Tailwind Zoom Pan Image Hover Effect
- 20Tailwind Color Channel Split Hover Effect
- 21Tailwind Duotone Image Hover Effect
- 22Tailwind Curtain Reveal Image Hover Effect
- 23Tailwind Ken Burns Image Hover Effect
- 24Tailwind Image Tilt Depth Hover Effect
- 25Tailwind Underline Slide Nav Hover Effect
- 26Tailwind Highlight Fill Nav Hover Effect
- 27Tailwind Strikethrough Hover Link Effect
- 28Tailwind Inline Word Swap Hover Effect
- 29Tailwind Dot Trail Cursor Hover Effect
- 30Tailwind Magnetic Cursor Pull Hover Effect
Tailwind Magnetic Liquid Button Hover Effect
Four tactile button hovers — liquid fill, blob morph, surface-tension droplet and rubber squash-and-stretch. Fill layers are before: pseudo-elements scaled from zero; the label rides above on relative z-10.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="thv-07 w-full min-h-svh grid place-items-center bg-thv07-bg font-thv07-sans px-6 py-14">
<div class="w-[min(760px,100%)] grid grid-cols-[repeat(auto-fit,minmax(240px,1fr))] gap-10">
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-green bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-green cursor-pointer transition-colors duration-350 before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-green before:origin-bottom before:scale-y-0 before:transition-transform before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:before:scale-y-100 focus-visible:text-white focus-visible:before:scale-y-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-green motion-reduce:before:transition-none"><span class="relative z-10">Liquid Fill</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">scale-Y fill</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-teal bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-teal cursor-pointer transition-[color,border-radius] duration-500 ease-[cubic-bezier(.4,0,.2,1)] before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-teal before:rounded-lg before:scale-0 before:transition-[transform,border-radius] before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:rounded-[60%_40%_70%_30%/40%_70%_30%_60%] hover:before:scale-100 hover:before:rounded-[60%_40%_70%_30%/40%_70%_30%_60%] focus-visible:text-white focus-visible:before:scale-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-teal motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative z-10">Blob Morph</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">border-radius keyframe</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-emerald bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-emerald cursor-pointer transition-colors duration-350 after:content-[''] after:absolute after:top-1/2 after:left-1/2 after:-z-10 after:w-[200%] after:h-[200%] after:rounded-full after:bg-thv07-emerald after:-translate-x-1/2 after:-translate-y-1/2 after:scale-0 after:transition-transform after:duration-500 after:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:after:scale-100 focus-visible:text-white focus-visible:after:scale-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-emerald motion-reduce:after:transition-none"><span class="relative z-10">Surface Tension</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">centred droplet expand</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-mint bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-mint cursor-pointer transition-[transform,color] duration-200 ease-[cubic-bezier(.4,0,.2,1)] before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-mint before:origin-bottom before:scale-y-0 before:transition-transform before:duration-350 hover:text-black hover:scale-x-[1.06] hover:scale-y-[0.93] hover:before:scale-y-100 focus-visible:text-black focus-visible:before:scale-y-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-mint active:scale-x-[0.97] active:scale-y-[1.04] motion-reduce:transition-none motion-reduce:hover:scale-100 motion-reduce:before:transition-none"><span class="relative z-10">Rubber Stretch</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">squash-and-stretch</span>
</div>
</div>
</section><section class="thv-07 w-full min-h-svh grid place-items-center bg-thv07-bg font-thv07-sans px-6 py-14">
<div class="w-[min(760px,100%)] grid grid-cols-[repeat(auto-fit,minmax(240px,1fr))] gap-10">
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-green bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-green cursor-pointer transition-colors duration-350 before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-green before:origin-bottom before:scale-y-0 before:transition-transform before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:before:scale-y-100 focus-visible:text-white focus-visible:before:scale-y-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-green motion-reduce:before:transition-none"><span class="relative z-10">Liquid Fill</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">scale-Y fill</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-teal bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-teal cursor-pointer transition-[color,border-radius] duration-500 ease-[cubic-bezier(.4,0,.2,1)] before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-teal before:rounded-lg before:scale-0 before:transition-[transform,border-radius] before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:rounded-[60%_40%_70%_30%/40%_70%_30%_60%] hover:before:scale-100 hover:before:rounded-[60%_40%_70%_30%/40%_70%_30%_60%] focus-visible:text-white focus-visible:before:scale-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-teal motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative z-10">Blob Morph</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">border-radius keyframe</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-emerald bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-emerald cursor-pointer transition-colors duration-350 after:content-[''] after:absolute after:top-1/2 after:left-1/2 after:-z-10 after:w-[200%] after:h-[200%] after:rounded-full after:bg-thv07-emerald after:-translate-x-1/2 after:-translate-y-1/2 after:scale-0 after:transition-transform after:duration-500 after:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:after:scale-100 focus-visible:text-white focus-visible:after:scale-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-emerald motion-reduce:after:transition-none"><span class="relative z-10">Surface Tension</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">centred droplet expand</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-mint bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-mint cursor-pointer transition-[transform,color] duration-200 ease-[cubic-bezier(.4,0,.2,1)] before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-mint before:origin-bottom before:scale-y-0 before:transition-transform before:duration-350 hover:text-black hover:scale-x-[1.06] hover:scale-y-[0.93] hover:before:scale-y-100 focus-visible:text-black focus-visible:before:scale-y-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-mint active:scale-x-[0.97] active:scale-y-[1.04] motion-reduce:transition-none motion-reduce:hover:scale-100 motion-reduce:before:transition-none"><span class="relative z-10">Rubber Stretch</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">squash-and-stretch</span>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-thv07-bg: #030d09;
--color-thv07-bg: oklch(0.13 0.02 165);
--color-thv07-dim: #4b6157;
--color-thv07-dim: oklch(0.45 0.02 165);
--color-thv07-green: #10b981;
--color-thv07-green: oklch(0.7 0.15 163);
--color-thv07-teal: #0d9488;
--color-thv07-teal: oklch(0.6 0.12 180);
--color-thv07-emerald: #059669;
--color-thv07-emerald: oklch(0.6 0.13 163);
--color-thv07-mint: #6ee7b7;
--color-thv07-mint: oklch(0.86 0.13 165);
--font-thv07-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-07 {
width: 100%;
min-height: 100svh;
}
.thv-07 ::selection {
background: var(--color-thv07-green);
color: #fff;
}@import "tailwindcss";
@theme {
--color-thv07-bg: #030d09;
--color-thv07-bg: oklch(0.13 0.02 165);
--color-thv07-dim: #4b6157;
--color-thv07-dim: oklch(0.45 0.02 165);
--color-thv07-green: #10b981;
--color-thv07-green: oklch(0.7 0.15 163);
--color-thv07-teal: #0d9488;
--color-thv07-teal: oklch(0.6 0.12 180);
--color-thv07-emerald: #059669;
--color-thv07-emerald: oklch(0.6 0.13 163);
--color-thv07-mint: #6ee7b7;
--color-thv07-mint: oklch(0.86 0.13 165);
--font-thv07-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-07 {
width: 100%;
min-height: 100svh;
}
.thv-07 ::selection {
background: var(--color-thv07-green);
color: #fff;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-thv07-bg: #030d09;
--color-thv07-bg: oklch(0.13 0.02 165);
--color-thv07-dim: #4b6157;
--color-thv07-dim: oklch(0.45 0.02 165);
--color-thv07-green: #10b981;
--color-thv07-green: oklch(0.7 0.15 163);
--color-thv07-teal: #0d9488;
--color-thv07-teal: oklch(0.6 0.12 180);
--color-thv07-emerald: #059669;
--color-thv07-emerald: oklch(0.6 0.13 163);
--color-thv07-mint: #6ee7b7;
--color-thv07-mint: oklch(0.86 0.13 165);
--font-thv07-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-07 {
width: 100%;
min-height: 100svh;
}
.thv-07 ::selection {
background: var(--color-thv07-green);
color: #fff;
}@import "tailwindcss";
@theme {
--color-thv07-bg: #030d09;
--color-thv07-bg: oklch(0.13 0.02 165);
--color-thv07-dim: #4b6157;
--color-thv07-dim: oklch(0.45 0.02 165);
--color-thv07-green: #10b981;
--color-thv07-green: oklch(0.7 0.15 163);
--color-thv07-teal: #0d9488;
--color-thv07-teal: oklch(0.6 0.12 180);
--color-thv07-emerald: #059669;
--color-thv07-emerald: oklch(0.6 0.13 163);
--color-thv07-mint: #6ee7b7;
--color-thv07-mint: oklch(0.86 0.13 165);
--font-thv07-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-07 {
width: 100%;
min-height: 100svh;
}
.thv-07 ::selection {
background: var(--color-thv07-green);
color: #fff;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;800&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The droplet's centring bug cannot recur in the port: there is no percentage-margin utility to reach for, and
-translate-x-1/2is element-relative by definition. - UI change from the CSS original: every button is a real
<button type="button">withmin-h-11, a focus ring, and afocus-visible:twin for the fill — the fill now plays for keyboard users. motion-reduce:hover:scale-100on the rubber button cancels only the squash; the colour and fill still change, so the state is never silently lost.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Magnetic Liquid Button Hover Effect
Source: https://codefronts.com/motion/tailwind-css-hover-effects/tailwind-magnetic-liquid-button-hover-effect/
Four tactile button hovers — liquid fill, blob morph, surface-tension droplet and rubber squash-and-stretch. Fill layers are before: pseudo-elements scaled from zero; the label rides above on relative z-10.
## HTML
```html
<section class="thv-07 w-full min-h-svh grid place-items-center bg-thv07-bg font-thv07-sans px-6 py-14">
<div class="w-[min(760px,100%)] grid grid-cols-[repeat(auto-fit,minmax(240px,1fr))] gap-10">
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-green bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-green cursor-pointer transition-colors duration-350 before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-green before:origin-bottom before:scale-y-0 before:transition-transform before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:before:scale-y-100 focus-visible:text-white focus-visible:before:scale-y-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-green motion-reduce:before:transition-none"><span class="relative z-10">Liquid Fill</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">scale-Y fill</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-teal bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-teal cursor-pointer transition-[color,border-radius] duration-500 ease-[cubic-bezier(.4,0,.2,1)] before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-teal before:rounded-lg before:scale-0 before:transition-[transform,border-radius] before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:rounded-[60%_40%_70%_30%/40%_70%_30%_60%] hover:before:scale-100 hover:before:rounded-[60%_40%_70%_30%/40%_70%_30%_60%] focus-visible:text-white focus-visible:before:scale-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-teal motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative z-10">Blob Morph</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">border-radius keyframe</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-emerald bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-emerald cursor-pointer transition-colors duration-350 after:content-[''] after:absolute after:top-1/2 after:left-1/2 after:-z-10 after:w-[200%] after:h-[200%] after:rounded-full after:bg-thv07-emerald after:-translate-x-1/2 after:-translate-y-1/2 after:scale-0 after:transition-transform after:duration-500 after:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:after:scale-100 focus-visible:text-white focus-visible:after:scale-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-emerald motion-reduce:after:transition-none"><span class="relative z-10">Surface Tension</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">centred droplet expand</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-mint bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-mint cursor-pointer transition-[transform,color] duration-200 ease-[cubic-bezier(.4,0,.2,1)] before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-mint before:origin-bottom before:scale-y-0 before:transition-transform before:duration-350 hover:text-black hover:scale-x-[1.06] hover:scale-y-[0.93] hover:before:scale-y-100 focus-visible:text-black focus-visible:before:scale-y-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-mint active:scale-x-[0.97] active:scale-y-[1.04] motion-reduce:transition-none motion-reduce:hover:scale-100 motion-reduce:before:transition-none"><span class="relative z-10">Rubber Stretch</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">squash-and-stretch</span>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-thv07-bg: #030d09;
--color-thv07-bg: oklch(0.13 0.02 165);
--color-thv07-dim: #4b6157;
--color-thv07-dim: oklch(0.45 0.02 165);
--color-thv07-green: #10b981;
--color-thv07-green: oklch(0.7 0.15 163);
--color-thv07-teal: #0d9488;
--color-thv07-teal: oklch(0.6 0.12 180);
--color-thv07-emerald: #059669;
--color-thv07-emerald: oklch(0.6 0.13 163);
--color-thv07-mint: #6ee7b7;
--color-thv07-mint: oklch(0.86 0.13 165);
--font-thv07-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-07 {
width: 100%;
min-height: 100svh;
}
.thv-07 ::selection {
background: var(--color-thv07-green);
color: #fff;
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Magnetic Liquid Button Hover Effect
Source: https://codefronts.com/motion/tailwind-css-hover-effects/tailwind-magnetic-liquid-button-hover-effect/
Four tactile button hovers — liquid fill, blob morph, surface-tension droplet and rubber squash-and-stretch. Fill layers are before: pseudo-elements scaled from zero; the label rides above on relative z-10.
## HTML
```html
<section class="thv-07 w-full min-h-svh grid place-items-center bg-thv07-bg font-thv07-sans px-6 py-14">
<div class="w-[min(760px,100%)] grid grid-cols-[repeat(auto-fit,minmax(240px,1fr))] gap-10">
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-green bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-green cursor-pointer transition-colors duration-350 before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-green before:origin-bottom before:scale-y-0 before:transition-transform before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:before:scale-y-100 focus-visible:text-white focus-visible:before:scale-y-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-green motion-reduce:before:transition-none"><span class="relative z-10">Liquid Fill</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">scale-Y fill</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-teal bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-teal cursor-pointer transition-[color,border-radius] duration-500 ease-[cubic-bezier(.4,0,.2,1)] before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-teal before:rounded-lg before:scale-0 before:transition-[transform,border-radius] before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:rounded-[60%_40%_70%_30%/40%_70%_30%_60%] hover:before:scale-100 hover:before:rounded-[60%_40%_70%_30%/40%_70%_30%_60%] focus-visible:text-white focus-visible:before:scale-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-teal motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative z-10">Blob Morph</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">border-radius keyframe</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-emerald bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-emerald cursor-pointer transition-colors duration-350 after:content-[''] after:absolute after:top-1/2 after:left-1/2 after:-z-10 after:w-[200%] after:h-[200%] after:rounded-full after:bg-thv07-emerald after:-translate-x-1/2 after:-translate-y-1/2 after:scale-0 after:transition-transform after:duration-500 after:ease-[cubic-bezier(.4,0,.2,1)] hover:text-white hover:after:scale-100 focus-visible:text-white focus-visible:after:scale-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-emerald motion-reduce:after:transition-none"><span class="relative z-10">Surface Tension</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">centred droplet expand</span>
</div>
<div class="flex flex-col items-center gap-5 px-8 py-12 rounded-2xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden isolate min-h-11 px-9 py-3.5 rounded-lg border-2 border-thv07-mint bg-transparent text-base font-semibold tracking-[0.06em] text-thv07-mint cursor-pointer transition-[transform,color] duration-200 ease-[cubic-bezier(.4,0,.2,1)] before:content-[''] before:absolute before:inset-0 before:-z-10 before:bg-thv07-mint before:origin-bottom before:scale-y-0 before:transition-transform before:duration-350 hover:text-black hover:scale-x-[1.06] hover:scale-y-[0.93] hover:before:scale-y-100 focus-visible:text-black focus-visible:before:scale-y-100 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv07-mint active:scale-x-[0.97] active:scale-y-[1.04] motion-reduce:transition-none motion-reduce:hover:scale-100 motion-reduce:before:transition-none"><span class="relative z-10">Rubber Stretch</span></button>
<span class="text-[11px] tracking-[0.15em] uppercase text-thv07-dim">squash-and-stretch</span>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-thv07-bg: #030d09;
--color-thv07-bg: oklch(0.13 0.02 165);
--color-thv07-dim: #4b6157;
--color-thv07-dim: oklch(0.45 0.02 165);
--color-thv07-green: #10b981;
--color-thv07-green: oklch(0.7 0.15 163);
--color-thv07-teal: #0d9488;
--color-thv07-teal: oklch(0.6 0.12 180);
--color-thv07-emerald: #059669;
--color-thv07-emerald: oklch(0.6 0.13 163);
--color-thv07-mint: #6ee7b7;
--color-thv07-mint: oklch(0.86 0.13 165);
--font-thv07-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-07 {
width: 100%;
min-height: 100svh;
}
.thv-07 ::selection {
background: var(--color-thv07-green);
color: #fff;
}
```How this works
The fill is a pseudo-element, the label is a span. before:absolute before:inset-0 before:-z-0 plus relative z-10 on the inner <span> is the whole stacking arrangement; overflow-hidden clips the overshoot.
The droplet fix survives the port. Percentage margins resolve against the parent's width on both axes, which is why the CSS version's margin:-100% 0 0 -100% flung the circle off the top of a wide button. Tailwind's translate utilities are element-relative, so after:-translate-x-1/2 after:-translate-y-1/2 centres correctly and the scale rides in the same transform.
Squash and stretch is two utilities. hover:scale-x-[1.06] hover:scale-y-[0.93] then active:scale-x-[0.97] active:scale-y-[1.04] — the bounce-back state that makes the button feel physical.
Make it yours
- Viscosity is
before:duration-250(snappy) tobefore:duration-500(thick). - Tint the fill with an alpha token, e.g.
before:bg-thv07-green/70, for tinted glass. - Push the blob further:
hover:rounded-[70%_30%_60%_40%/40%_60%_70%_30%].
Gotchas — read before shipping
overflow-hiddenis required for the droplet and fill, and it also clips any outershadow-*— put glows on a wrapper if you need both.before:needs an explicitbefore:content-['']or nothing renders.- Animating
border-radiusrepaints rather than composites; a page full of blobs will jank on low-end hardware.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Transitions and transforms only; the floor is Tailwind v4's generated sheet.