36 Tailwind CSS Button Hover Effects
04 / 36

All 36 in 36 Tailwind CSS Button Hover Effects

  1. 01Tailwind Magnetic Ripple Attraction Button Hover Effect
  2. 02Tailwind Cyberpunk Holographic Glitch Grid Button
  3. 03Tailwind Frosted Glassmorphism Shimmer Glow Button
  4. 04Tailwind Organic Blob Morph Button Hover Effect
  5. 05Tailwind Dual-Line Intersection Border Draw Button
  6. 06Tailwind Isometric Tactile 3D Depress Button
  7. 07Tailwind Infinite Sliding Kinetic Marquee Button
  8. 08Tailwind Chroma Conic Gradient Border Spin Button
  9. 09Tailwind Minimalist Border & Outline Drawing Hover Effects
  10. 10Tailwind Modern 3D Skeuomorphic Button Press Effects
  11. 11Tailwind Neo-Brutalist & Cyberpunk Button Glow Effects
  12. 12Tailwind Sliding Background Color Wipe Button Effects
  13. 13Tailwind Liquid Fill & Organic Morphing Button Effects
  14. 14Tailwind Kinetic Text Flip & Icon Reveal Button Effects
  15. 15Tailwind Liquid Wave Fill Button Hover Effect
  16. 16Tailwind Magnetic Border Drift Button
  17. 17Tailwind Glitch Slice Button Hover Effect
  18. 18Tailwind Neon Pulse Glow Button Hover Effect
  19. 19Tailwind Split Reveal Curtain Button Effect
  20. 20Tailwind Diagonal Shutter Sweep Button Effect
  21. 21Tailwind Elastic Lift Spring Button Hover Effect
  22. 22Tailwind Center Underline Draw Link Button Effects
  23. 23Tailwind 3D Flip Card Button Hover Effect
  24. 24Tailwind Particle Burst Confetti Button Effect
  25. 25Tailwind Slide Doors Closing Panel Button Effect
  26. 26Tailwind Typewriter Retype Terminal Button Effect
  27. 27Tailwind Hard Shadow Shift Flat Button Effect
  28. 28Tailwind Material Ripple Wave Button Effect
  29. 29Tailwind Rainbow Gradient Border Spin Button
  30. 30Tailwind Morph Shape Silhouette Button Effects
  31. 31Tailwind Icon Slide In Directional Button Effect
  32. 32Tailwind Cursor Spotlight Glow Button
  33. 33Tailwind Stagger Fill Equaliser Button Effect
  34. 34Tailwind Sunburst Expand Radiant Button Effect
  35. 35Tailwind 3D Press Plunger Key Button Effect
  36. 36Tailwind Add-to-Cart Liquid Glass Ripple Button
Pure TailwindMIT licensed

Tailwind Organic Blob Morph Button Hover Effect

A playful CTA that starts as a soft organic blob and, on hover, resolves into a clean structured pill — great for creative studios and friendly product pages. The port's interesting constraint: an eight-value border-radius is not a design-scale value, so it stays an arbitrary property, and that is the right answer.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<div class="tbh-04-group w-full min-h-svh flex flex-wrap">
<section class="tbh-04a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh04-sans bg-[radial-gradient(120%_120%_at_30%_0%,var(--color-tbh04a-lift),var(--color-tbh04a-bg))]" aria-label="Blob morph button">
  <button type="button" class="grid place-items-center min-w-[180px] cursor-pointer border-0 px-10 py-6 text-[17px] font-extrabold text-white bg-[linear-gradient(150deg,color-mix(in_oklab,var(--color-tbh04a-acc)_82%,white),var(--color-tbh04a-acc))] shadow-[0_18px_36px_-16px_color-mix(in_oklab,var(--color-tbh04a-acc)_70%,transparent)] [border-radius:42%_58%_63%_37%_/_45%_38%_62%_55%] animate-tbh04a-breathe transition-[border-radius,translate,scale] duration-[600ms] ease-[cubic-bezier(.2,.9,.2,1)] hover:rounded-full hover:-translate-y-[3px] hover:[animation-play-state:paused] focus-visible:rounded-full focus-visible:-translate-y-[3px] focus-visible:[animation-play-state:paused] active:translate-y-0 active:scale-[.97] focus-visible:outline-3 focus-visible:outline-tbh04a-acc focus-visible:outline-offset-4 motion-reduce:animate-none motion-reduce:transition-[border-radius] motion-reduce:hover:translate-y-0">
    Say hello
  </button>
</section>
<section class="tbh-04b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh04-sans bg-tbh04b-bg" aria-label="Squircle morph button">
  <button type="button" aria-label="Play" class="grid place-items-center w-24 h-24 cursor-pointer border-0 text-[26px] text-white bg-[linear-gradient(150deg,color-mix(in_oklab,var(--color-tbh04b-acc)_80%,white),var(--color-tbh04b-acc))] shadow-[0_18px_40px_-16px_var(--color-tbh04b-acc)] [border-radius:34%_66%_62%_38%_/_40%_42%_58%_60%] transition-[border-radius,scale] duration-[550ms] ease-[cubic-bezier(.2,.9,.2,1)] hover:rounded-[50%] hover:scale-[1.08] focus-visible:rounded-[50%] focus-visible:scale-[1.08] active:scale-[.96] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-4 motion-reduce:transition-[border-radius] motion-reduce:hover:scale-100">
    <span aria-hidden="true">&#9654;</span>
  </button>
</section>
</div>
@import "tailwindcss";

@theme {
  --color-tbh04a-acc: #f2734a;
  --color-tbh04a-acc: oklch(0.68 0.17 25);
  --color-tbh04a-bg: #ffe1d3;
  --color-tbh04a-bg: oklch(0.92 0.04 45);
  --color-tbh04a-lift: #fff3ec;
  --color-tbh04a-lift: oklch(0.97 0.015 45);
  --color-tbh04b-acc: #9a5cf0;
  --color-tbh04b-acc: oklch(0.62 0.18 300);
  --color-tbh04b-bg: #141020;
  --color-tbh04b-bg: oklch(0.18 0.03 290);
  --font-tbh04-sans: 'Space Grotesk', system-ui, sans-serif;
  --animate-tbh04a-breathe: tbh04a-breathe 7s ease-in-out infinite;
}
/* Stays CSS: a keyframe interpolating two eight-value border-radius sets. Both ends must use
   the identical syntax form, or the browser refuses to interpolate and snaps instead. */

@keyframes tbh04a-breathe {
  0%,
    100% {
    border-radius: 42% 58% 63% 37% / 45% 38% 62% 55%;
  }

  50% {
    border-radius: 60% 40% 38% 62% / 55% 62% 38% 45%;
  }
}

.tbh-04-group {
  width: 100%;
  min-height: 100svh;
}

.tbh-04a,
.tbh-04b {
  min-height: 100svh;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<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.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-tbh04a-acc: #f2734a;
  --color-tbh04a-acc: oklch(0.68 0.17 25);
  --color-tbh04a-bg: #ffe1d3;
  --color-tbh04a-bg: oklch(0.92 0.04 45);
  --color-tbh04a-lift: #fff3ec;
  --color-tbh04a-lift: oklch(0.97 0.015 45);
  --color-tbh04b-acc: #9a5cf0;
  --color-tbh04b-acc: oklch(0.62 0.18 300);
  --color-tbh04b-bg: #141020;
  --color-tbh04b-bg: oklch(0.18 0.03 290);
  --font-tbh04-sans: 'Space Grotesk', system-ui, sans-serif;
  --animate-tbh04a-breathe: tbh04a-breathe 7s ease-in-out infinite;
}
/* Stays CSS: a keyframe interpolating two eight-value border-radius sets. Both ends must use
   the identical syntax form, or the browser refuses to interpolate and snaps instead. */

@keyframes tbh04a-breathe {
  0%,
    100% {
    border-radius: 42% 58% 63% 37% / 45% 38% 62% 55%;
  }

  50% {
    border-radius: 60% 40% 38% 62% / 55% 62% 38% 45%;
  }
}

.tbh-04-group {
  width: 100%;
  min-height: 100svh;
}

.tbh-04a,
.tbh-04b {
  min-height: 100svh;
}
3Fonts used by this demooptional — skip if you have your own type stack
<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&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • The one demo in the batch where the central value resists utilities entirely. An eight-value border-radius is a one-off silhouette, not a scale step, so [border-radius:...] is the idiomatic answer rather than a workaround — and the _/_ escape is the only syntax subtlety in it.
  • animation-play-state is the other CSS-shaped hole: no utility, no variant shorthand, so hover:[animation-play-state:paused]. Worth knowing before you reach for a JS class toggle to do the same thing.
  • UI change from the CSS original: both designs now mirror every hover state on focus-visible: (the original morphed on focus but not consistently), and the press states are split into active:translate-y-0 active:scale-[.97] so the lift and the squash no longer overwrite each other.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
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 Organic Blob Morph Button Hover Effect
Source: https://codefronts.com/motion/tailwind-css-button-hover-effects/tailwind-organic-blob-morph-button-hover-effect/

A playful CTA that starts as a soft organic blob and, on hover, resolves into a clean structured pill &mdash; great for creative studios and friendly product pages. The port's interesting constraint: an eight-value border-radius is not a design-scale value, so it stays an arbitrary property, and that is the right answer.
## HTML
```html
<div class="tbh-04-group w-full min-h-svh flex flex-wrap">
<section class="tbh-04a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh04-sans bg-[radial-gradient(120%_120%_at_30%_0%,var(--color-tbh04a-lift),var(--color-tbh04a-bg))]" aria-label="Blob morph button">
  <button type="button" class="grid place-items-center min-w-[180px] cursor-pointer border-0 px-10 py-6 text-[17px] font-extrabold text-white bg-[linear-gradient(150deg,color-mix(in_oklab,var(--color-tbh04a-acc)_82%,white),var(--color-tbh04a-acc))] shadow-[0_18px_36px_-16px_color-mix(in_oklab,var(--color-tbh04a-acc)_70%,transparent)] [border-radius:42%_58%_63%_37%_/_45%_38%_62%_55%] animate-tbh04a-breathe transition-[border-radius,translate,scale] duration-[600ms] ease-[cubic-bezier(.2,.9,.2,1)] hover:rounded-full hover:-translate-y-[3px] hover:[animation-play-state:paused] focus-visible:rounded-full focus-visible:-translate-y-[3px] focus-visible:[animation-play-state:paused] active:translate-y-0 active:scale-[.97] focus-visible:outline-3 focus-visible:outline-tbh04a-acc focus-visible:outline-offset-4 motion-reduce:animate-none motion-reduce:transition-[border-radius] motion-reduce:hover:translate-y-0">
    Say hello
  </button>
</section>
<section class="tbh-04b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh04-sans bg-tbh04b-bg" aria-label="Squircle morph button">
  <button type="button" aria-label="Play" class="grid place-items-center w-24 h-24 cursor-pointer border-0 text-[26px] text-white bg-[linear-gradient(150deg,color-mix(in_oklab,var(--color-tbh04b-acc)_80%,white),var(--color-tbh04b-acc))] shadow-[0_18px_40px_-16px_var(--color-tbh04b-acc)] [border-radius:34%_66%_62%_38%_/_40%_42%_58%_60%] transition-[border-radius,scale] duration-[550ms] ease-[cubic-bezier(.2,.9,.2,1)] hover:rounded-[50%] hover:scale-[1.08] focus-visible:rounded-[50%] focus-visible:scale-[1.08] active:scale-[.96] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-4 motion-reduce:transition-[border-radius] motion-reduce:hover:scale-100">
    <span aria-hidden="true">&#9654;</span>
  </button>
</section>
</div>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tbh04a-acc: #f2734a;
  --color-tbh04a-acc: oklch(0.68 0.17 25);
  --color-tbh04a-bg: #ffe1d3;
  --color-tbh04a-bg: oklch(0.92 0.04 45);
  --color-tbh04a-lift: #fff3ec;
  --color-tbh04a-lift: oklch(0.97 0.015 45);
  --color-tbh04b-acc: #9a5cf0;
  --color-tbh04b-acc: oklch(0.62 0.18 300);
  --color-tbh04b-bg: #141020;
  --color-tbh04b-bg: oklch(0.18 0.03 290);
  --font-tbh04-sans: 'Space Grotesk', system-ui, sans-serif;
  --animate-tbh04a-breathe: tbh04a-breathe 7s ease-in-out infinite;
}
/* Stays CSS: a keyframe interpolating two eight-value border-radius sets. Both ends must use
   the identical syntax form, or the browser refuses to interpolate and snaps instead. */

@keyframes tbh04a-breathe {
  0%,
    100% {
    border-radius: 42% 58% 63% 37% / 45% 38% 62% 55%;
  }

  50% {
    border-radius: 60% 40% 38% 62% / 55% 62% 38% 45%;
  }
}

.tbh-04-group {
  width: 100%;
  min-height: 100svh;
}

.tbh-04a,
.tbh-04b {
  min-height: 100svh;
}
```

How this works

Why the radius is not a utility. Tailwind's rounded-* scale exists so that corner radii stay consistent across a product. A hand-tuned eight-value blob is the opposite of that: a one-off shape belonging to one element. Writing it as [border-radius:...] states that honestly, and the underscore escape carries the multi-value syntax through intact.

Hover both resolves and freezes. The blob breathes at rest via a keyframe that transitions between two radius sets. On hover, hover:rounded-full transitions to a symmetric pill while hover:[animation-play-state:paused] stops the wobble fighting it — the CSS original needed the same two declarations, but they sat in two different rules.

Design B is the icon case. A 96px squircle blob that morphs to a true circle and scales up 8% — the same technique at a size where the shape, not the label, is the whole button. Its accessible name comes from aria-label, since the glyph is decorative.

Make it yours

  • Blob personality: the eight radius stops. Keep both keyframe ends in the same syntax form or the animation will not interpolate at all.
  • Idle calm: drop animate-tbh04a-breathe and the shape simply sits still until hover.
  • Morph speed: duration-[600ms] with ease-[cubic-bezier(.2,.9,.2,1)] — long enough to read as organic, short enough to feel responsive.
  • Target shape: hover:rounded-full on A, hover:rounded-[50%] on B; a rounded-2xl target reads as 'app icon' instead.

Gotchas — read before shipping

  • Multi-value border-radius interpolates only between two same-syntax forms. A four-value resting shape and an eight-value hover target will snap rather than morph.
  • Do not animate width to reshape the button — that relayouts the stage on every frame. Let the radius do the work.
  • Centre the label with grid place-items-center, not absolute offsets, so it stays put while the silhouette breathes.
  • [animation-play-state:paused] has no utility and no variant shorthand; the arbitrary property is the only form, and it must be written on the same element that carries animate-*.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Multi-value border-radius transitions are universal; the optional SVG path d morph mentioned in the CSS original remains Chromium-only, which is why this port keeps the radius technique.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Arbitraryneeds bracket syntax

Plain CSSno Tailwind surface

Search CodeFronts

Loading…