36 Tailwind CSS Button Hover Effects
09 / 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 Minimalist Border & Outline Drawing Hover Effects

A refined understated CTA for editorial and luxury layouts: at rest it's just text, and on hover a hairline stroke draws itself continuously around the rounded-rectangle perimeter. Tailwind reaches SVG presentation attributes the same way it reaches anything else it has no scale for — arbitrary properties.

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-09-group w-full min-h-svh flex flex-wrap">
<section class="tbh-09a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh09-sans bg-tbh09a-stage" aria-label="Outline drawing button">
  <button type="button" class="group/btn relative cursor-pointer border-0 bg-transparent px-[42px] py-5 text-[15px] font-bold uppercase tracking-[0.06em] text-tbh09a-line focus-visible:outline-none">
    <svg aria-hidden="true" preserveAspectRatio="none" class="absolute inset-0 w-full h-full overflow-visible">
      <rect x="1" y="1" rx="12" ry="12" class="fill-none [stroke:var(--color-tbh09a-line)] [stroke-width:2] [width:calc(100%-2px)] [height:calc(100%-2px)] [stroke-dasharray:0_1000] transition-[stroke-dasharray] duration-[800ms] ease-out group-hover/btn:[stroke-dasharray:1000_0] group-focus-visible/btn:[stroke-dasharray:1000_0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:1000_0] motion-reduce:opacity-50"></rect>
    </svg>
    <span class="relative z-[1] group-focus-visible/btn:underline group-focus-visible/btn:underline-offset-4">Read the story</span>
  </button>
</section>
<section class="tbh-09b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh09-sans bg-tbh09b-stage" aria-label="Underline to box button">
  <button type="button" class="relative cursor-pointer border-0 bg-transparent px-8 py-4 text-base font-bold text-tbh09b-line focus-visible:outline-none before:content-[''] before:absolute before:left-0 before:bottom-0 before:w-full before:h-0.5 before:bg-tbh09b-line before:origin-left after:content-[''] after:absolute after:inset-0 after:border-2 after:border-b-0 after:border-tbh09b-line after:[clip-path:inset(0_0_100%_0)] after:transition-[clip-path] after:duration-[350ms] after:delay-150 after:ease-out hover:after:[clip-path:inset(0_0_0_0)] focus-visible:after:[clip-path:inset(0_0_0_0)] focus-visible:underline focus-visible:underline-offset-4 motion-reduce:after:transition-none motion-reduce:after:delay-0">
    <span>Discover more</span>
  </button>
</section>
</div>
@import "tailwindcss";

@theme {
  --color-tbh09a-line: #4a5068;
  --color-tbh09a-line: oklch(0.45 0.03 265);
  --color-tbh09a-stage: #f6f5f1;
  --color-tbh09a-stage: oklch(0.97 0.006 90);
  --color-tbh09b-line: #b04a2f;
  --color-tbh09b-line: oklch(0.5 0.14 25);
  --color-tbh09b-stage: #faf6f4;
  --color-tbh09b-stage: oklch(0.98 0.008 35);
  --font-tbh09-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing stays CSS: SVG presentation attributes are reachable as arbitrary properties,
   which is the useful discovery in this port. */

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

.tbh-09a,
.tbh-09b {
  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-tbh09a-line: #4a5068;
  --color-tbh09a-line: oklch(0.45 0.03 265);
  --color-tbh09a-stage: #f6f5f1;
  --color-tbh09a-stage: oklch(0.97 0.006 90);
  --color-tbh09b-line: #b04a2f;
  --color-tbh09b-line: oklch(0.5 0.14 25);
  --color-tbh09b-stage: #faf6f4;
  --color-tbh09b-stage: oklch(0.98 0.008 35);
  --font-tbh09-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing stays CSS: SVG presentation attributes are reachable as arbitrary properties,
   which is the useful discovery in this port. */

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

.tbh-09a,
.tbh-09b {
  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.

  • SVG presentation attributes turn out to port cleanly: [stroke:var(--color-tbh09a-line)], [stroke-width:2] and [stroke-dasharray:0_1000] all compile, and fill-none even has a real utility. The <rect> now carries its resting stroke, its hover target and its reduced-motion state in one class list.
  • transition-[stroke-dasharray] is the part worth remembering — Tailwind's arbitrary transition-property accepts any animatable property name, including SVG ones, so nothing about this effect needed a stylesheet.
  • UI change from the CSS original: design A's hover draw now also fires on group-focus-visible/btn:, and its reduced-motion state shows the frame at 50% opacity rather than nothing — keyboard and reduced-motion users previously got the label alone.
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 Minimalist Border & Outline Drawing Hover Effects
Source: https://codefronts.com/motion/tailwind-css-button-hover-effects/tailwind-minimalist-border-outline-drawing-hover-effects/

A refined understated CTA for editorial and luxury layouts: at rest it's just text, and on hover a hairline stroke draws itself continuously around the rounded-rectangle perimeter. Tailwind reaches SVG presentation attributes the same way it reaches anything else it has no scale for &mdash; arbitrary properties.
## HTML
```html
<div class="tbh-09-group w-full min-h-svh flex flex-wrap">
<section class="tbh-09a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh09-sans bg-tbh09a-stage" aria-label="Outline drawing button">
  <button type="button" class="group/btn relative cursor-pointer border-0 bg-transparent px-[42px] py-5 text-[15px] font-bold uppercase tracking-[0.06em] text-tbh09a-line focus-visible:outline-none">
    <svg aria-hidden="true" preserveAspectRatio="none" class="absolute inset-0 w-full h-full overflow-visible">
      <rect x="1" y="1" rx="12" ry="12" class="fill-none [stroke:var(--color-tbh09a-line)] [stroke-width:2] [width:calc(100%-2px)] [height:calc(100%-2px)] [stroke-dasharray:0_1000] transition-[stroke-dasharray] duration-[800ms] ease-out group-hover/btn:[stroke-dasharray:1000_0] group-focus-visible/btn:[stroke-dasharray:1000_0] motion-reduce:transition-none motion-reduce:[stroke-dasharray:1000_0] motion-reduce:opacity-50"></rect>
    </svg>
    <span class="relative z-[1] group-focus-visible/btn:underline group-focus-visible/btn:underline-offset-4">Read the story</span>
  </button>
</section>
<section class="tbh-09b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh09-sans bg-tbh09b-stage" aria-label="Underline to box button">
  <button type="button" class="relative cursor-pointer border-0 bg-transparent px-8 py-4 text-base font-bold text-tbh09b-line focus-visible:outline-none before:content-[''] before:absolute before:left-0 before:bottom-0 before:w-full before:h-0.5 before:bg-tbh09b-line before:origin-left after:content-[''] after:absolute after:inset-0 after:border-2 after:border-b-0 after:border-tbh09b-line after:[clip-path:inset(0_0_100%_0)] after:transition-[clip-path] after:duration-[350ms] after:delay-150 after:ease-out hover:after:[clip-path:inset(0_0_0_0)] focus-visible:after:[clip-path:inset(0_0_0_0)] focus-visible:underline focus-visible:underline-offset-4 motion-reduce:after:transition-none motion-reduce:after:delay-0">
    <span>Discover more</span>
  </button>
</section>
</div>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tbh09a-line: #4a5068;
  --color-tbh09a-line: oklch(0.45 0.03 265);
  --color-tbh09a-stage: #f6f5f1;
  --color-tbh09a-stage: oklch(0.97 0.006 90);
  --color-tbh09b-line: #b04a2f;
  --color-tbh09b-line: oklch(0.5 0.14 25);
  --color-tbh09b-stage: #faf6f4;
  --color-tbh09b-stage: oklch(0.98 0.008 35);
  --font-tbh09-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing stays CSS: SVG presentation attributes are reachable as arbitrary properties,
   which is the useful discovery in this port. */

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

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

How this works

The stroke is hidden by arithmetic. stroke-dasharray: 0 1000 means a zero-length dash followed by a 1000px gap — an invisible stroke. Hover swaps the two numbers, and because dasharray interpolates, the dash grows around the perimeter as the gap shrinks. One transition, one continuous line.

Why a rect and not a border. A CSS border cannot be drawn progressively; an SVG stroke can. The <svg> sits absolute inset-0 with preserveAspectRatio="none" so the rect tracks the button's real size whatever the label length.

Design B stages two shapes. The bottom rule exists at rest (so the button reads as a link), and hover reveals the remaining three sides top-down via clip-path, 150ms later. The delay is what makes it read as one gesture: rule first, then frame.

Make it yours

  • Draw speed: duration-[800ms]. Slower reads as luxury, faster as utility.
  • Stroke weight and colour: [stroke-width:2] and [stroke:var(--color-tbh09a-line)].
  • Draw origin: reverse the dasharray pair to start the sweep from the opposite corner.
  • Design B's stagger: after:delay-150 — drop it and the underline and frame appear as one flat box.

Gotchas — read before shipping

  • The dasharray total must exceed the true perimeter or the loop visibly fails to close. 1000 is generous for a button; measure if you scale the pattern up.
  • Add [vector-effect:non-scaling-stroke] if the SVG is ever scaled, or the hairline thickens with it.
  • Both designs replace the focus outline with a visible non-motion indicator (an underline on the label). That is the only acceptable way to drop an outline — never remove it for the drawn frame alone, which does not exist until hover.
  • Design A's rect is inset by 1px (x="1" y="1" with calc(100%-2px) sizing) so the 2px stroke is not clipped at the SVG edge.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

SVG stroke-dash transitions and clip-path: inset() are universal; with CSS unavailable both buttons remain readable text labels.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Arbitraryneeds bracket syntax

Search CodeFronts

Loading…