36 Tailwind CSS Button Hover Effects
12 / 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 Sliding Background Color Wipe Button Effects

The dependable one: a solid colour wipes in and the label colour swaps to stay readable — the most requested hover in professional product UIs, in three directions. The port's whole subtlety is one utility: delay-[120ms] on the label's colour transition.

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-12-group w-full min-h-svh flex flex-wrap">
<section class="tbh-12a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh12-sans bg-tbh12a-stage" aria-label="Colour wipe button">
  <button type="button" class="relative isolate overflow-hidden cursor-pointer rounded-[10px] border-2 border-tbh12a-fill px-[38px] py-4 text-base font-bold text-tbh12a-fill bg-transparent transition-colors duration-[250ms] delay-[120ms] before:content-[''] before:absolute before:inset-0 before:z-0 before:bg-tbh12a-fill before:scale-x-0 before:origin-left before:transition-transform before:duration-400 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-tbh12a-onfill hover:before:scale-x-100 focus-visible:text-tbh12a-onfill focus-visible:before:scale-x-100 focus-visible:outline-3 focus-visible:outline-tbh12a-fill focus-visible:outline-offset-[3px] motion-reduce:transition-none motion-reduce:before:transition-none">
    <span class="relative z-[1]">Contact sales</span>
  </button>
</section>
<section class="tbh-12b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh12-sans bg-tbh12b-stage" aria-label="Bottom-up fill button">
  <button type="button" class="relative isolate overflow-hidden cursor-pointer rounded-[10px] border-2 border-tbh12b-fill px-[42px] py-[17px] text-base font-extrabold text-tbh12b-fill bg-transparent transition-colors duration-[250ms] delay-[140ms] before:content-[''] before:absolute before:inset-0 before:z-0 before:bg-tbh12b-fill before:scale-y-0 before:origin-bottom before:transition-transform before:duration-[380ms] before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-tbh12b-onfill hover:before:scale-y-100 focus-visible:text-tbh12b-onfill focus-visible:before:scale-y-100 focus-visible:outline-3 focus-visible:outline-tbh12b-fill focus-visible:outline-offset-[3px] motion-reduce:transition-none motion-reduce:before:transition-none">
    <span class="relative z-[1]">Get the app</span>
  </button>
</section>
<section class="tbh-12c flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh12-sans bg-tbh12c-stage" aria-label="Center-out fill button">
  <button type="button" class="relative isolate overflow-hidden cursor-pointer rounded-full border-2 border-tbh12c-fill px-[42px] py-[17px] text-base font-extrabold text-tbh12c-fill bg-transparent transition-colors duration-[250ms] delay-[120ms] before:content-[''] before:absolute before:inset-0 before:z-0 before:bg-tbh12c-fill before:scale-x-0 before:origin-center before:transition-transform before:duration-400 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-tbh12c-onfill hover:before:scale-x-100 focus-visible:text-tbh12c-onfill focus-visible:before:scale-x-100 focus-visible:outline-3 focus-visible:outline-tbh12c-fill focus-visible:outline-offset-[3px] motion-reduce:transition-none motion-reduce:before:transition-none">
    <span class="relative z-[1]">Start trial</span>
  </button>
</section>
</div>
@import "tailwindcss";

@theme {
  --color-tbh12a-fill: #3f6ad0;
  --color-tbh12a-fill: oklch(0.55 0.17 255);
  --color-tbh12a-onfill: #ffffff;
  --color-tbh12a-onfill: oklch(1 0 0);
  --color-tbh12a-stage: #eef1f6;
  --color-tbh12a-stage: oklch(0.95 0.008 255);
  --color-tbh12b-fill: #4cb87a;
  --color-tbh12b-fill: oklch(0.6 0.16 150);
  --color-tbh12b-onfill: #04180d;
  --color-tbh12b-onfill: oklch(0.2 0.05 150);
  --color-tbh12b-stage: #0d160f;
  --color-tbh12b-stage: oklch(0.16 0.02 150);
  --color-tbh12c-fill: #d2543c;
  --color-tbh12c-fill: oklch(0.58 0.18 20);
  --color-tbh12c-onfill: #ffffff;
  --color-tbh12c-onfill: oklch(1 0 0);
  --color-tbh12c-stage: #1a0f10;
  --color-tbh12c-stage: oklch(0.18 0.02 20);
  --font-tbh12-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing stays CSS. Three directions, three origin utilities, one delayed colour swap. */

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

.tbh-12a,
.tbh-12b,
.tbh-12c {
  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-tbh12a-fill: #3f6ad0;
  --color-tbh12a-fill: oklch(0.55 0.17 255);
  --color-tbh12a-onfill: #ffffff;
  --color-tbh12a-onfill: oklch(1 0 0);
  --color-tbh12a-stage: #eef1f6;
  --color-tbh12a-stage: oklch(0.95 0.008 255);
  --color-tbh12b-fill: #4cb87a;
  --color-tbh12b-fill: oklch(0.6 0.16 150);
  --color-tbh12b-onfill: #04180d;
  --color-tbh12b-onfill: oklch(0.2 0.05 150);
  --color-tbh12b-stage: #0d160f;
  --color-tbh12b-stage: oklch(0.16 0.02 150);
  --color-tbh12c-fill: #d2543c;
  --color-tbh12c-fill: oklch(0.58 0.18 20);
  --color-tbh12c-onfill: #ffffff;
  --color-tbh12c-onfill: oklch(1 0 0);
  --color-tbh12c-stage: #1a0f10;
  --color-tbh12c-stage: oklch(0.18 0.02 20);
  --font-tbh12-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing stays CSS. Three directions, three origin utilities, one delayed colour swap. */

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

.tbh-12a,
.tbh-12b,
.tbh-12c {
  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 batch's most ordinary effect and its most instructive port: the direction of the wipe is now literally one word in the class list (before:origin-left / origin-bottom / origin-center), so the three variants are diffable at a glance instead of three near-identical rule blocks.
  • delay-[120ms] on transition-colors is the whole reason this pattern looks professional, and putting it in the class list is the first time it is visible to whoever copies the markup. In the CSS version it was the second number in a shorthand.
  • UI change from the CSS original: the fill and the ink swap now both fire on focus-visible:, and the -onfill colours were promoted to tokens so the on-fill contrast is stated rather than assumed — design B's dark ink on green is the one that needed it.
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 Sliding Background Color Wipe Button Effects
Source: https://codefronts.com/motion/tailwind-css-button-hover-effects/tailwind-sliding-background-color-wipe-button-effects/

The dependable one: a solid colour wipes in and the label colour swaps to stay readable &mdash; the most requested hover in professional product UIs, in three directions. The port's whole subtlety is one utility: delay-[120ms] on the label's colour transition.
## HTML
```html
<div class="tbh-12-group w-full min-h-svh flex flex-wrap">
<section class="tbh-12a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh12-sans bg-tbh12a-stage" aria-label="Colour wipe button">
  <button type="button" class="relative isolate overflow-hidden cursor-pointer rounded-[10px] border-2 border-tbh12a-fill px-[38px] py-4 text-base font-bold text-tbh12a-fill bg-transparent transition-colors duration-[250ms] delay-[120ms] before:content-[''] before:absolute before:inset-0 before:z-0 before:bg-tbh12a-fill before:scale-x-0 before:origin-left before:transition-transform before:duration-400 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-tbh12a-onfill hover:before:scale-x-100 focus-visible:text-tbh12a-onfill focus-visible:before:scale-x-100 focus-visible:outline-3 focus-visible:outline-tbh12a-fill focus-visible:outline-offset-[3px] motion-reduce:transition-none motion-reduce:before:transition-none">
    <span class="relative z-[1]">Contact sales</span>
  </button>
</section>
<section class="tbh-12b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh12-sans bg-tbh12b-stage" aria-label="Bottom-up fill button">
  <button type="button" class="relative isolate overflow-hidden cursor-pointer rounded-[10px] border-2 border-tbh12b-fill px-[42px] py-[17px] text-base font-extrabold text-tbh12b-fill bg-transparent transition-colors duration-[250ms] delay-[140ms] before:content-[''] before:absolute before:inset-0 before:z-0 before:bg-tbh12b-fill before:scale-y-0 before:origin-bottom before:transition-transform before:duration-[380ms] before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-tbh12b-onfill hover:before:scale-y-100 focus-visible:text-tbh12b-onfill focus-visible:before:scale-y-100 focus-visible:outline-3 focus-visible:outline-tbh12b-fill focus-visible:outline-offset-[3px] motion-reduce:transition-none motion-reduce:before:transition-none">
    <span class="relative z-[1]">Get the app</span>
  </button>
</section>
<section class="tbh-12c flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh12-sans bg-tbh12c-stage" aria-label="Center-out fill button">
  <button type="button" class="relative isolate overflow-hidden cursor-pointer rounded-full border-2 border-tbh12c-fill px-[42px] py-[17px] text-base font-extrabold text-tbh12c-fill bg-transparent transition-colors duration-[250ms] delay-[120ms] before:content-[''] before:absolute before:inset-0 before:z-0 before:bg-tbh12c-fill before:scale-x-0 before:origin-center before:transition-transform before:duration-400 before:ease-[cubic-bezier(.4,0,.2,1)] hover:text-tbh12c-onfill hover:before:scale-x-100 focus-visible:text-tbh12c-onfill focus-visible:before:scale-x-100 focus-visible:outline-3 focus-visible:outline-tbh12c-fill focus-visible:outline-offset-[3px] motion-reduce:transition-none motion-reduce:before:transition-none">
    <span class="relative z-[1]">Start trial</span>
  </button>
</section>
</div>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tbh12a-fill: #3f6ad0;
  --color-tbh12a-fill: oklch(0.55 0.17 255);
  --color-tbh12a-onfill: #ffffff;
  --color-tbh12a-onfill: oklch(1 0 0);
  --color-tbh12a-stage: #eef1f6;
  --color-tbh12a-stage: oklch(0.95 0.008 255);
  --color-tbh12b-fill: #4cb87a;
  --color-tbh12b-fill: oklch(0.6 0.16 150);
  --color-tbh12b-onfill: #04180d;
  --color-tbh12b-onfill: oklch(0.2 0.05 150);
  --color-tbh12b-stage: #0d160f;
  --color-tbh12b-stage: oklch(0.16 0.02 150);
  --color-tbh12c-fill: #d2543c;
  --color-tbh12c-fill: oklch(0.58 0.18 20);
  --color-tbh12c-onfill: #ffffff;
  --color-tbh12c-onfill: oklch(1 0 0);
  --color-tbh12c-stage: #1a0f10;
  --color-tbh12c-stage: oklch(0.18 0.02 20);
  --font-tbh12-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing stays CSS. Three directions, three origin utilities, one delayed colour swap. */

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

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

How this works

Scale, never width. A before: layer at inset-0 scaled to 0 on one axis costs nothing to animate and reflows nothing; animating width would relayout the button on every frame. This is the demo everyone writes first and writes wrong.

The delay is the craft. Without delay-[120ms] the label turns white while the button is still mostly transparent, and for ~100ms the text is unreadable. With it, the colour swap lands just as the fill passes under the text. One utility, and it is the difference between this effect feeling cheap and feeling paid-for.

Three origins, three products. Left-to-right reads as progress, bottom-up as filling, centre-out as emphasis. Same twelve utilities otherwise — which is the argument for keeping all three in one entry.

Make it yours

  • Direction: swap before:origin-left for origin-right, origin-top, or a diagonal via before:skew-x-[-12deg] with a wider layer.
  • Wipe speed: before:duration-400 with ease-[cubic-bezier(.4,0,.2,1)].
  • Label flip timing: delay-[120ms] — roughly a third of the wipe duration is the sweet spot.
  • Palette: each design's --color-tbh12*-fill and -onfill pair; the border, the fill, the ring and the hover ink all read them.

Gotchas — read before shipping

  • Delay the label swap or the text is briefly unreadable against a half-filled button — the one real accessibility trap in this pattern.
  • Both label colours must clear 4.5:1: text-tbh12a-fill on the stage AND text-tbh12a-onfill on the fill. Checking only the resting state is the usual mistake.
  • Use before:scale-x-0, not before:w-0. The visual result is identical and the cost is not.
  • Under motion-reduce: the fill is pinned present (motion-reduce:hover:before:scale-x-100 with transitions off), so the hover still communicates — it just does not travel.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Transforms, pseudo-elements and transition-delay are universal; with CSS unavailable each button is a normal bordered CTA.

Techniques used in this demo

Search CodeFronts

Loading…