35 / 36
All 36 in 36 Tailwind CSS Button Hover Effects
- 01Tailwind Magnetic Ripple Attraction Button Hover Effect
- 02Tailwind Cyberpunk Holographic Glitch Grid Button
- 03Tailwind Frosted Glassmorphism Shimmer Glow Button
- 04Tailwind Organic Blob Morph Button Hover Effect
- 05Tailwind Dual-Line Intersection Border Draw Button
- 06Tailwind Isometric Tactile 3D Depress Button
- 07Tailwind Infinite Sliding Kinetic Marquee Button
- 08Tailwind Chroma Conic Gradient Border Spin Button
- 09Tailwind Minimalist Border & Outline Drawing Hover Effects
- 10Tailwind Modern 3D Skeuomorphic Button Press Effects
- 11Tailwind Neo-Brutalist & Cyberpunk Button Glow Effects
- 12Tailwind Sliding Background Color Wipe Button Effects
- 13Tailwind Liquid Fill & Organic Morphing Button Effects
- 14Tailwind Kinetic Text Flip & Icon Reveal Button Effects
- 15Tailwind Liquid Wave Fill Button Hover Effect
- 16Tailwind Magnetic Border Drift Button
- 17Tailwind Glitch Slice Button Hover Effect
- 18Tailwind Neon Pulse Glow Button Hover Effect
- 19Tailwind Split Reveal Curtain Button Effect
- 20Tailwind Diagonal Shutter Sweep Button Effect
- 21Tailwind Elastic Lift Spring Button Hover Effect
- 22Tailwind Center Underline Draw Link Button Effects
- 23Tailwind 3D Flip Card Button Hover Effect
- 24Tailwind Particle Burst Confetti Button Effect
- 25Tailwind Slide Doors Closing Panel Button Effect
- 26Tailwind Typewriter Retype Terminal Button Effect
- 27Tailwind Hard Shadow Shift Flat Button Effect
- 28Tailwind Material Ripple Wave Button Effect
- 29Tailwind Rainbow Gradient Border Spin Button
- 30Tailwind Morph Shape Silhouette Button Effects
- 31Tailwind Icon Slide In Directional Button Effect
- 32Tailwind Cursor Spotlight Glow Button
- 33Tailwind Stagger Fill Equaliser Button Effect
- 34Tailwind Sunburst Expand Radiant Button Effect
- 35Tailwind 3D Press Plunger Key Button Effect
- 36Tailwind Add-to-Cart Liquid Glass Ripple Button
Tailwind 3D Press Plunger Key Button Effect
A deeply tactile CTA on a thick 3D base like a plunger key: on press it drives straight down while the base compresses in lockstep — a vertical plunge, distinct from entry 06's isometric tilt. The invariant is arithmetic, and the port puts all three stages where you can check it.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<div class="tbh-35-group w-full min-h-svh flex flex-wrap">
<section class="tbh-35a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[60px] font-tbh35-sans bg-tbh35a-stage" aria-label="3D plunger press button">
<button type="button" class="cursor-pointer border-0 rounded-[14px] px-[42px] py-4 text-[17px] font-extrabold text-white bg-tbh35a-cap -translate-y-2 shadow-[0_8px_0_var(--color-tbh35a-base),0_14px_18px_-6px_oklch(0_0_0/0.5)] transition-[translate,box-shadow] duration-[120ms] ease-out hover:-translate-y-2.5 hover:shadow-[0_10px_0_var(--color-tbh35a-base),0_18px_22px_-6px_oklch(0_0_0/0.5)] focus-visible:-translate-y-2.5 focus-visible:shadow-[0_10px_0_var(--color-tbh35a-base),0_18px_22px_-6px_oklch(0_0_0/0.5)] active:-translate-y-0.5 active:shadow-[0_2px_0_var(--color-tbh35a-base),0_6px_10px_-4px_oklch(0_0_0/0.5)] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow] motion-reduce:duration-100">
Confirm
</button>
</section>
<section class="tbh-35b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[60px] font-tbh35-mono bg-tbh35b-stage" aria-label="Chunky keycap button">
<button type="button" class="cursor-pointer border-0 rounded-xl px-10 py-[18px] text-base font-extrabold text-tbh35b-ink bg-[linear-gradient(180deg,white,var(--color-tbh35b-cap))] -translate-y-2.5 shadow-[0_10px_0_var(--color-tbh35b-base),inset_0_2px_0_oklch(1_0_0),0_16px_20px_-6px_oklch(0_0_0/0.5)] transition-[translate,box-shadow] duration-100 ease-out active:-translate-y-0.5 active:shadow-[0_2px_0_var(--color-tbh35b-base),inset_0_2px_0_oklch(1_0_0),0_6px_10px_-4px_oklch(0_0_0/0.5)] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow]">
Enter ⏎
</button>
</section>
</div><div class="tbh-35-group w-full min-h-svh flex flex-wrap">
<section class="tbh-35a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[60px] font-tbh35-sans bg-tbh35a-stage" aria-label="3D plunger press button">
<button type="button" class="cursor-pointer border-0 rounded-[14px] px-[42px] py-4 text-[17px] font-extrabold text-white bg-tbh35a-cap -translate-y-2 shadow-[0_8px_0_var(--color-tbh35a-base),0_14px_18px_-6px_oklch(0_0_0/0.5)] transition-[translate,box-shadow] duration-[120ms] ease-out hover:-translate-y-2.5 hover:shadow-[0_10px_0_var(--color-tbh35a-base),0_18px_22px_-6px_oklch(0_0_0/0.5)] focus-visible:-translate-y-2.5 focus-visible:shadow-[0_10px_0_var(--color-tbh35a-base),0_18px_22px_-6px_oklch(0_0_0/0.5)] active:-translate-y-0.5 active:shadow-[0_2px_0_var(--color-tbh35a-base),0_6px_10px_-4px_oklch(0_0_0/0.5)] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow] motion-reduce:duration-100">
Confirm
</button>
</section>
<section class="tbh-35b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[60px] font-tbh35-mono bg-tbh35b-stage" aria-label="Chunky keycap button">
<button type="button" class="cursor-pointer border-0 rounded-xl px-10 py-[18px] text-base font-extrabold text-tbh35b-ink bg-[linear-gradient(180deg,white,var(--color-tbh35b-cap))] -translate-y-2.5 shadow-[0_10px_0_var(--color-tbh35b-base),inset_0_2px_0_oklch(1_0_0),0_16px_20px_-6px_oklch(0_0_0/0.5)] transition-[translate,box-shadow] duration-100 ease-out active:-translate-y-0.5 active:shadow-[0_2px_0_var(--color-tbh35b-base),inset_0_2px_0_oklch(1_0_0),0_6px_10px_-4px_oklch(0_0_0/0.5)] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow]">
Enter ⏎
</button>
</section>
</div>@import "tailwindcss";
@theme {
--color-tbh35a-cap: #e0563c;
--color-tbh35a-cap: oklch(0.62 0.2 25);
--color-tbh35a-base: #8f3220;
--color-tbh35a-base: oklch(0.4 0.15 25);
--color-tbh35a-stage: #160a08;
--color-tbh35a-stage: oklch(0.17 0.03 25);
--color-tbh35b-cap: #dfe2ea;
--color-tbh35b-cap: oklch(0.9 0.02 260);
--color-tbh35b-base: #9298a8;
--color-tbh35b-base: oklch(0.62 0.03 260);
--color-tbh35b-ink: #2a2f42;
--color-tbh35b-ink: oklch(0.32 0.03 265);
--color-tbh35b-stage: #1c2030;
--color-tbh35b-stage: oklch(0.25 0.03 265);
--font-tbh35-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tbh35-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Nothing stays CSS: three shadow stacks and three matching translates. */
.tbh-35-group {
width: 100%;
min-height: 100svh;
}
.tbh-35a,
.tbh-35b {
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbh35a-cap: #e0563c;
--color-tbh35a-cap: oklch(0.62 0.2 25);
--color-tbh35a-base: #8f3220;
--color-tbh35a-base: oklch(0.4 0.15 25);
--color-tbh35a-stage: #160a08;
--color-tbh35a-stage: oklch(0.17 0.03 25);
--color-tbh35b-cap: #dfe2ea;
--color-tbh35b-cap: oklch(0.9 0.02 260);
--color-tbh35b-base: #9298a8;
--color-tbh35b-base: oklch(0.62 0.03 260);
--color-tbh35b-ink: #2a2f42;
--color-tbh35b-ink: oklch(0.32 0.03 265);
--color-tbh35b-stage: #1c2030;
--color-tbh35b-stage: oklch(0.25 0.03 265);
--font-tbh35-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tbh35-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Nothing stays CSS: three shadow stacks and three matching translates. */
.tbh-35-group {
width: 100%;
min-height: 100svh;
}
.tbh-35a,
.tbh-35b {
min-height: 100svh;
}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-tbh35a-cap: #e0563c;
--color-tbh35a-cap: oklch(0.62 0.2 25);
--color-tbh35a-base: #8f3220;
--color-tbh35a-base: oklch(0.4 0.15 25);
--color-tbh35a-stage: #160a08;
--color-tbh35a-stage: oklch(0.17 0.03 25);
--color-tbh35b-cap: #dfe2ea;
--color-tbh35b-cap: oklch(0.9 0.02 260);
--color-tbh35b-base: #9298a8;
--color-tbh35b-base: oklch(0.62 0.03 260);
--color-tbh35b-ink: #2a2f42;
--color-tbh35b-ink: oklch(0.32 0.03 265);
--color-tbh35b-stage: #1c2030;
--color-tbh35b-stage: oklch(0.25 0.03 265);
--font-tbh35-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tbh35-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Nothing stays CSS: three shadow stacks and three matching translates. */
.tbh-35-group {
width: 100%;
min-height: 100svh;
}
.tbh-35a,
.tbh-35b {
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbh35a-cap: #e0563c;
--color-tbh35a-cap: oklch(0.62 0.2 25);
--color-tbh35a-base: #8f3220;
--color-tbh35a-base: oklch(0.4 0.15 25);
--color-tbh35a-stage: #160a08;
--color-tbh35a-stage: oklch(0.17 0.03 25);
--color-tbh35b-cap: #dfe2ea;
--color-tbh35b-cap: oklch(0.9 0.02 260);
--color-tbh35b-base: #9298a8;
--color-tbh35b-base: oklch(0.62 0.03 260);
--color-tbh35b-ink: #2a2f42;
--color-tbh35b-ink: oklch(0.32 0.03 265);
--color-tbh35b-stage: #1c2030;
--color-tbh35b-stage: oklch(0.25 0.03 265);
--font-tbh35-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tbh35-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Nothing stays CSS: three shadow stacks and three matching translates. */
.tbh-35-group {
width: 100%;
min-height: 100svh;
}
.tbh-35a,
.tbh-35b {
min-height: 100svh;
}<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@500;700&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@500;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The collection's closing argument for utilities: a three-stage tactile press whose entire correctness is an arithmetic relationship between a translate and a shadow depth, now written in one place where that relationship can be read rather than reconstructed from three rule blocks.
- Design B deliberately has no hover state, which is much more visible as an absence in a class list than as a missing rule in a stylesheet — the kind of intentional omission that usually gets 'fixed' by the next person to touch the file.
- UI change from the CSS original: design A's hover lift now fires on
focus-visible:too, and the focus ring offset was raised to 5px on both so it clears the 8–10px hard base instead of sitting inside it.
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 3D Press Plunger Key Button Effect
Source: https://codefronts.com/motion/tailwind-css-button-hover-effects/tailwind-3d-press-plunger-key-button-effect/
A deeply tactile CTA on a thick 3D base like a plunger key: on press it drives straight down while the base compresses in lockstep — a vertical plunge, distinct from entry 06's isometric tilt. The invariant is arithmetic, and the port puts all three stages where you can check it.
## HTML
```html
<div class="tbh-35-group w-full min-h-svh flex flex-wrap">
<section class="tbh-35a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[60px] font-tbh35-sans bg-tbh35a-stage" aria-label="3D plunger press button">
<button type="button" class="cursor-pointer border-0 rounded-[14px] px-[42px] py-4 text-[17px] font-extrabold text-white bg-tbh35a-cap -translate-y-2 shadow-[0_8px_0_var(--color-tbh35a-base),0_14px_18px_-6px_oklch(0_0_0/0.5)] transition-[translate,box-shadow] duration-[120ms] ease-out hover:-translate-y-2.5 hover:shadow-[0_10px_0_var(--color-tbh35a-base),0_18px_22px_-6px_oklch(0_0_0/0.5)] focus-visible:-translate-y-2.5 focus-visible:shadow-[0_10px_0_var(--color-tbh35a-base),0_18px_22px_-6px_oklch(0_0_0/0.5)] active:-translate-y-0.5 active:shadow-[0_2px_0_var(--color-tbh35a-base),0_6px_10px_-4px_oklch(0_0_0/0.5)] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow] motion-reduce:duration-100">
Confirm
</button>
</section>
<section class="tbh-35b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[60px] font-tbh35-mono bg-tbh35b-stage" aria-label="Chunky keycap button">
<button type="button" class="cursor-pointer border-0 rounded-xl px-10 py-[18px] text-base font-extrabold text-tbh35b-ink bg-[linear-gradient(180deg,white,var(--color-tbh35b-cap))] -translate-y-2.5 shadow-[0_10px_0_var(--color-tbh35b-base),inset_0_2px_0_oklch(1_0_0),0_16px_20px_-6px_oklch(0_0_0/0.5)] transition-[translate,box-shadow] duration-100 ease-out active:-translate-y-0.5 active:shadow-[0_2px_0_var(--color-tbh35b-base),inset_0_2px_0_oklch(1_0_0),0_6px_10px_-4px_oklch(0_0_0/0.5)] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow]">
Enter ⏎
</button>
</section>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbh35a-cap: #e0563c;
--color-tbh35a-cap: oklch(0.62 0.2 25);
--color-tbh35a-base: #8f3220;
--color-tbh35a-base: oklch(0.4 0.15 25);
--color-tbh35a-stage: #160a08;
--color-tbh35a-stage: oklch(0.17 0.03 25);
--color-tbh35b-cap: #dfe2ea;
--color-tbh35b-cap: oklch(0.9 0.02 260);
--color-tbh35b-base: #9298a8;
--color-tbh35b-base: oklch(0.62 0.03 260);
--color-tbh35b-ink: #2a2f42;
--color-tbh35b-ink: oklch(0.32 0.03 265);
--color-tbh35b-stage: #1c2030;
--color-tbh35b-stage: oklch(0.25 0.03 265);
--font-tbh35-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tbh35-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Nothing stays CSS: three shadow stacks and three matching translates. */
.tbh-35-group {
width: 100%;
min-height: 100svh;
}
.tbh-35a,
.tbh-35b {
min-height: 100svh;
}
```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 3D Press Plunger Key Button Effect
Source: https://codefronts.com/motion/tailwind-css-button-hover-effects/tailwind-3d-press-plunger-key-button-effect/
A deeply tactile CTA on a thick 3D base like a plunger key: on press it drives straight down while the base compresses in lockstep — a vertical plunge, distinct from entry 06's isometric tilt. The invariant is arithmetic, and the port puts all three stages where you can check it.
## HTML
```html
<div class="tbh-35-group w-full min-h-svh flex flex-wrap">
<section class="tbh-35a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[60px] font-tbh35-sans bg-tbh35a-stage" aria-label="3D plunger press button">
<button type="button" class="cursor-pointer border-0 rounded-[14px] px-[42px] py-4 text-[17px] font-extrabold text-white bg-tbh35a-cap -translate-y-2 shadow-[0_8px_0_var(--color-tbh35a-base),0_14px_18px_-6px_oklch(0_0_0/0.5)] transition-[translate,box-shadow] duration-[120ms] ease-out hover:-translate-y-2.5 hover:shadow-[0_10px_0_var(--color-tbh35a-base),0_18px_22px_-6px_oklch(0_0_0/0.5)] focus-visible:-translate-y-2.5 focus-visible:shadow-[0_10px_0_var(--color-tbh35a-base),0_18px_22px_-6px_oklch(0_0_0/0.5)] active:-translate-y-0.5 active:shadow-[0_2px_0_var(--color-tbh35a-base),0_6px_10px_-4px_oklch(0_0_0/0.5)] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow] motion-reduce:duration-100">
Confirm
</button>
</section>
<section class="tbh-35b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[60px] font-tbh35-mono bg-tbh35b-stage" aria-label="Chunky keycap button">
<button type="button" class="cursor-pointer border-0 rounded-xl px-10 py-[18px] text-base font-extrabold text-tbh35b-ink bg-[linear-gradient(180deg,white,var(--color-tbh35b-cap))] -translate-y-2.5 shadow-[0_10px_0_var(--color-tbh35b-base),inset_0_2px_0_oklch(1_0_0),0_16px_20px_-6px_oklch(0_0_0/0.5)] transition-[translate,box-shadow] duration-100 ease-out active:-translate-y-0.5 active:shadow-[0_2px_0_var(--color-tbh35b-base),inset_0_2px_0_oklch(1_0_0),0_6px_10px_-4px_oklch(0_0_0/0.5)] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow]">
Enter ⏎
</button>
</section>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbh35a-cap: #e0563c;
--color-tbh35a-cap: oklch(0.62 0.2 25);
--color-tbh35a-base: #8f3220;
--color-tbh35a-base: oklch(0.4 0.15 25);
--color-tbh35a-stage: #160a08;
--color-tbh35a-stage: oklch(0.17 0.03 25);
--color-tbh35b-cap: #dfe2ea;
--color-tbh35b-cap: oklch(0.9 0.02 260);
--color-tbh35b-base: #9298a8;
--color-tbh35b-base: oklch(0.62 0.03 260);
--color-tbh35b-ink: #2a2f42;
--color-tbh35b-ink: oklch(0.32 0.03 265);
--color-tbh35b-stage: #1c2030;
--color-tbh35b-stage: oklch(0.25 0.03 265);
--font-tbh35-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tbh35-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Nothing stays CSS: three shadow stacks and three matching translates. */
.tbh-35-group {
width: 100%;
min-height: 100svh;
}
.tbh-35a,
.tbh-35b {
min-height: 100svh;
}
```How this works
Travel plus residual depth must equal resting depth. Resting: 8px up on an 8px base. Pressed: 2px up on a 2px base. The cap's top surface therefore drops exactly 6px while the base loses exactly 6px — which is why the key looks like it is compressing rather than sliding. Get it wrong and the button appears to detach from its own base.
Three stages, three class runs. Rest, hover (a millimetre higher, anticipating), press (bottomed out). In the CSS original those were three rule blocks each restating a translate and a two-layer shadow; here they sit in sequence and the arithmetic is checkable by reading left to right.
Design B is the keycap variant. No hover lift at all — a keyboard key does not rise when you hover it. Just rest and press, with a gradient face and an inset highlight doing the work that colour alone cannot.
Make it yours
- Key weight: the resting base depth and the matching press travel, changed together (8px is a chunky game key, 4px a UI button).
- Cap and base:
--color-tbh35a-cap/-base; the base must stay darker or the extrusion reads as a glow. - Press speed:
duration-[120ms]. Above ~160ms the key feels spongy. - Click flash: add
active:bg-[color-mix(in_oklab,var(--color-tbh35a-cap)_80%,white)]for a struck-key highlight.
Gotchas — read before shipping
- Press translate + residual shadow must equal the resting depth, or the cap and base separate visibly at the bottom of the stroke.
- Keep the base colour darker than the cap. This is the same rule as entry 06 and it is the difference between depth and a halo.
- No tilt here — that is entry 06. Mixing a
rotateinto this one produces a key that appears to be breaking off its mount. - Design B has no hover state on purpose; adding one makes a keycap behave like a button and loses the metaphor.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Stacked box-shadow and transforms are universal; nothing here needs a fallback beyond Tailwind v4's own floor.