51 Tailwind CSS Buttons
31 / 51

All 51 in 51 Tailwind CSS Buttons

  1. 01Tailwind Submit Button (Form Primary)
  2. 02Tailwind Primary and Secondary Button Pair
  3. 03Tailwind Ghost / Outline Button
  4. 04Tailwind Icon-Only Button with Accessible Tooltip
  5. 05Tailwind Gradient CTA Button
  6. 06Tailwind Loading Spinner Button (State Transition)
  7. 07Tailwind Disabled Button State (Full State Reference)
  8. 08Tailwind Button Group Component (Segmented Radio-Like)
  9. 09Tailwind Add to Cart Button
  10. 10Tailwind Download Progress Button
  11. 11Tailwind Like Heart Button
  12. 12Tailwind Confirm Delete Button
  13. 13Tailwind Play Pause Button
  14. 14Tailwind Subscribe Confetti Button
  15. 15Tailwind Magnetic Mercury Ripple Button
  16. 16Tailwind Brutalist Glitch Button
  17. 17Tailwind Neon Plasma Burst Button
  18. 18Tailwind Clay Press Button
  19. 19Tailwind Editorial Ink Spread Button
  20. 20Tailwind Particle Shard Burst Button
  21. 21Tailwind Brushed Brass Plate Button
  22. 22Tailwind Washi Paper Crane Button
  23. 23Tailwind Frosted Ice Cube Button
  24. 24Tailwind Vintage Typewriter Key Button
  25. 25Tailwind Lacquered Walnut Wood Button
  26. 26Tailwind Pharma Gel Capsule Button
  27. 27Tailwind Aged Copper Coin Button
  28. 28Tailwind Origami Fortune Cookie Button
  29. 29Tailwind Holographic Foil Sticker Button
  30. 30Tailwind Brutalist Concrete Slab Button
  31. 31Tailwind Mercury Bead Morph Button
  32. 32Tailwind Soft Pill Modern SaaS Button
  33. 33Tailwind Masking Tape Label Button
  34. 34Tailwind Obsidian Glass Shard Button
  35. 35Tailwind Wine Velvet Ribbon Button
  36. 36Tailwind LED Segment Display Button
  37. 37Tailwind Cassette Mixtape Label Button
  38. 38Tailwind Chalkboard Menu Button
  39. 39Tailwind Vinyl Record Sleeve Ripple Button
  40. 40Tailwind Polaroid Snapshot Button
  41. 41Tailwind Airline Boarding Pass Button
  42. 42Tailwind Aged Brass Subway Token Button
  43. 43Tailwind Vintage Rx Pharmacy Label Button
  44. 44Tailwind Bakelite Radio Dial Toggle Button
  45. 45Tailwind Regal Postage Stamp Button
  46. 46Tailwind Victorian Cigar Band Foil Button
  47. 47Tailwind Vintage Calculator Key Button
  48. 48Tailwind Toolbox Latch Spotlight Button
  49. 49Tailwind Receipt Paper Total Count-Up Button
  50. 50Tailwind IBM Punch Card Magnetic Follow Button
  51. 51Tailwind Brass Periscope Lens Button
Pure TailwindMIT licensed

Tailwind Mercury Bead Morph Button

A bead of mercury detaches from the button, stretches, and is reabsorbed on hover — genuine metaball merging from an SVG goo filter applied to plain CSS shapes. The filter is markup, the geometry is utilities, and the label sits outside the filtered layer so it stays sharp.

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="tb-31 w-full min-h-svh grid place-items-center font-tb31-sans antialiased p-[clamp(1.5rem,6vw,4rem)]">
  <svg aria-hidden="true" focusable="false" width="0" height="0" class="absolute size-0 overflow-hidden">
    <filter id="tb-31-goo">
      <feGaussianBlur in="SourceGraphic" stdDeviation="7" result="b"></feGaussianBlur>
      <feColorMatrix in="b" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 20 -9" result="g"></feColorMatrix>
      <feBlend in="SourceGraphic" in2="g"></feBlend>
    </filter>
  </svg>
  <button type="button" class="group relative cursor-pointer border-0 bg-transparent w-64 h-32 p-0 text-base font-bold tracking-[-0.01em] text-tb31-ink [-webkit-tap-highlight-color:transparent] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tb31-hg focus-visible:rounded-2xl disabled:cursor-not-allowed disabled:grayscale disabled:brightness-80">
    <span aria-hidden="true" class="absolute inset-0 z-10 [filter:url(#tb-31-goo)]">
      <span class="tb-31__metal absolute left-9 top-10 w-[8.2rem] h-[3.2rem] rounded-full bg-[length:8.2rem_3.2rem] bg-no-repeat bg-left-top"></span>
      <span class="tb-31__metal absolute left-9 top-10 size-[3.2rem] rounded-full bg-[length:8.2rem_3.2rem] bg-no-repeat bg-left-top transition-[translate,scale] duration-[750ms] ease-tb31-out group-hover:translate-x-[8.4rem] group-hover:scale-[0.62] group-focus-visible:translate-x-[8.4rem] group-focus-visible:scale-[0.62] group-active:scale-50 motion-reduce:transition-none"></span>
    </span>
    <span class="absolute z-30 left-[3.9rem] top-1/2 -translate-y-1/2 transition-[translate,color] duration-500 ease-tb31-out group-hover:translate-x-[0.4rem] motion-reduce:transition-none">Liquify</span>
  </button>
</div>
@import "tailwindcss";

@theme {
  --color-tb31-bg: #0c0e12;
  --color-tb31-bg: oklch(0.15 0.012 260);
  --color-tb31-hg: #c9d2dc;
  --color-tb31-hg: oklch(0.84 0.015 250);
  --color-tb31-hg-lo: #5c6672;
  --color-tb31-hg-lo: oklch(0.48 0.02 250);
  --color-tb31-ink: #0b0d11;
  --color-tb31-ink: oklch(0.14 0.01 260);
  --font-tb31-sans: "Space Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --ease-tb31-out: cubic-bezier(0.16, 1, 0.3, 1);
}

.tb-31 {
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  background: radial-gradient(36rem 22rem at 50% 45%, #1b2029, transparent 72%), var(--color-tb31-bg);
}
/* Both shapes paint the SAME gradient at the SAME size, so at rest the bead is
   pixel-identical to the pill's left cap and disappears into it completely.
   The goo threshold merges silhouettes, not tones. */

.tb-31__metal {
  background-image: radial-gradient(120% 120% at 30% 20%, #ffffff, transparent 55%), linear-gradient(160deg, var(--color-tb31-hg), var(--color-tb31-hg-lo));
}

@media (prefers-color-scheme: light) {
  .tb-31:not([data-theme="dark"]) {
    --color-tb31-bg: oklch(0.92 0.006 260);
  }
}

.tb-31[data-theme="light"] {
  --color-tb31-bg: oklch(0.92 0.006 260);
}

@media (forced-colors: active) {
  .tb-31 button > span:first-of-type {
    display: none;
  }

  .tb-31 button {
    border: 1px solid ButtonText;
    background: ButtonFace;
    width: auto;
    height: auto;
    padding: 1rem 2rem;
  }

  .tb-31 button > span:last-child {
    position: static;
    translate: none;
    color: ButtonText;
  }
}

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-tb31-bg: #0c0e12;
  --color-tb31-bg: oklch(0.15 0.012 260);
  --color-tb31-hg: #c9d2dc;
  --color-tb31-hg: oklch(0.84 0.015 250);
  --color-tb31-hg-lo: #5c6672;
  --color-tb31-hg-lo: oklch(0.48 0.02 250);
  --color-tb31-ink: #0b0d11;
  --color-tb31-ink: oklch(0.14 0.01 260);
  --font-tb31-sans: "Space Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --ease-tb31-out: cubic-bezier(0.16, 1, 0.3, 1);
}

.tb-31 {
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  background: radial-gradient(36rem 22rem at 50% 45%, #1b2029, transparent 72%), var(--color-tb31-bg);
}
/* Both shapes paint the SAME gradient at the SAME size, so at rest the bead is
   pixel-identical to the pill's left cap and disappears into it completely.
   The goo threshold merges silhouettes, not tones. */

.tb-31__metal {
  background-image: radial-gradient(120% 120% at 30% 20%, #ffffff, transparent 55%), linear-gradient(160deg, var(--color-tb31-hg), var(--color-tb31-hg-lo));
}

@media (prefers-color-scheme: light) {
  .tb-31:not([data-theme="dark"]) {
    --color-tb31-bg: oklch(0.92 0.006 260);
  }
}

.tb-31[data-theme="light"] {
  --color-tb31-bg: oklch(0.92 0.006 260);
}

@media (forced-colors: active) {
  .tb-31 button > span:first-of-type {
    display: none;
  }

  .tb-31 button {
    border: 1px solid ButtonText;
    background: ButtonFace;
    width: auto;
    height: auto;
    padding: 1rem 2rem;
  }

  .tb-31 button > span:last-child {
    position: static;
    translate: none;
    color: ButtonText;
  }
}
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@500;600;700&display=swap">

What changed in the port

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

  • Utilities: the filter reference, both shapes' geometry, the identical background sizing that makes the bead invisible at rest, the travel-and-pinch hover, the label's parallax and its z-30. CSS: the chrome gradient shared by both shapes — one recipe, two elements.
  • [filter:url(#tb-31-goo)] is a good reminder that not everything in a design is a style. The filter is a document resource with an id, and the utility's job is only to point at it.
  • The shared .tb-31__metal class exists because the pill and the bead must be identical in paint. Two copies of the gradient as arbitrary utilities would be two places for them to drift apart — and the drift is invisible until it shows as a disc behind the label.
  • A11y fix from the CSS original: the focus ring was outline-offset:2px on a transparent 16×8rem button, so the ring drew a large rectangle far from the visible pill. The port keeps the geometry but also fires the bead animation on group-focus-visible:, so a keyboard user sees the same state change a mouse user does — previously hover-only.
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 Mercury Bead Morph Button
Source: https://codefronts.com/components/tailwind-css-buttons/tailwind-mercury-bead-morph-button/

A bead of mercury detaches from the button, stretches, and is reabsorbed on hover — genuine metaball merging from an SVG goo filter applied to plain CSS shapes. The filter is markup, the geometry is utilities, and the label sits outside the filtered layer so it stays sharp.
## HTML
```html
<div class="tb-31 w-full min-h-svh grid place-items-center font-tb31-sans antialiased p-[clamp(1.5rem,6vw,4rem)]">
  <svg aria-hidden="true" focusable="false" width="0" height="0" class="absolute size-0 overflow-hidden">
    <filter id="tb-31-goo">
      <feGaussianBlur in="SourceGraphic" stdDeviation="7" result="b"></feGaussianBlur>
      <feColorMatrix in="b" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 20 -9" result="g"></feColorMatrix>
      <feBlend in="SourceGraphic" in2="g"></feBlend>
    </filter>
  </svg>
  <button type="button" class="group relative cursor-pointer border-0 bg-transparent w-64 h-32 p-0 text-base font-bold tracking-[-0.01em] text-tb31-ink [-webkit-tap-highlight-color:transparent] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tb31-hg focus-visible:rounded-2xl disabled:cursor-not-allowed disabled:grayscale disabled:brightness-80">
    <span aria-hidden="true" class="absolute inset-0 z-10 [filter:url(#tb-31-goo)]">
      <span class="tb-31__metal absolute left-9 top-10 w-[8.2rem] h-[3.2rem] rounded-full bg-[length:8.2rem_3.2rem] bg-no-repeat bg-left-top"></span>
      <span class="tb-31__metal absolute left-9 top-10 size-[3.2rem] rounded-full bg-[length:8.2rem_3.2rem] bg-no-repeat bg-left-top transition-[translate,scale] duration-[750ms] ease-tb31-out group-hover:translate-x-[8.4rem] group-hover:scale-[0.62] group-focus-visible:translate-x-[8.4rem] group-focus-visible:scale-[0.62] group-active:scale-50 motion-reduce:transition-none"></span>
    </span>
    <span class="absolute z-30 left-[3.9rem] top-1/2 -translate-y-1/2 transition-[translate,color] duration-500 ease-tb31-out group-hover:translate-x-[0.4rem] motion-reduce:transition-none">Liquify</span>
  </button>
</div>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tb31-bg: #0c0e12;
  --color-tb31-bg: oklch(0.15 0.012 260);
  --color-tb31-hg: #c9d2dc;
  --color-tb31-hg: oklch(0.84 0.015 250);
  --color-tb31-hg-lo: #5c6672;
  --color-tb31-hg-lo: oklch(0.48 0.02 250);
  --color-tb31-ink: #0b0d11;
  --color-tb31-ink: oklch(0.14 0.01 260);
  --font-tb31-sans: "Space Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --ease-tb31-out: cubic-bezier(0.16, 1, 0.3, 1);
}

.tb-31 {
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  background: radial-gradient(36rem 22rem at 50% 45%, #1b2029, transparent 72%), var(--color-tb31-bg);
}
/* Both shapes paint the SAME gradient at the SAME size, so at rest the bead is
   pixel-identical to the pill's left cap and disappears into it completely.
   The goo threshold merges silhouettes, not tones. */

.tb-31__metal {
  background-image: radial-gradient(120% 120% at 30% 20%, #ffffff, transparent 55%), linear-gradient(160deg, var(--color-tb31-hg), var(--color-tb31-hg-lo));
}

@media (prefers-color-scheme: light) {
  .tb-31:not([data-theme="dark"]) {
    --color-tb31-bg: oklch(0.92 0.006 260);
  }
}

.tb-31[data-theme="light"] {
  --color-tb31-bg: oklch(0.92 0.006 260);
}

@media (forced-colors: active) {
  .tb-31 button > span:first-of-type {
    display: none;
  }

  .tb-31 button {
    border: 1px solid ButtonText;
    background: ButtonFace;
    width: auto;
    height: auto;
    padding: 1rem 2rem;
  }

  .tb-31 button > span:last-child {
    position: static;
    translate: none;
    color: ButtonText;
  }
}
```

How this works

The filter is two primitives and stays in the markup. Blur everything together, then push alpha through a steep curve so overlapping blurs snap into one continuous shape:

<feGaussianBlur stdDeviation="7" result="b"/>
<feColorMatrix in="b" values="… 0 0 0 20 -9" result="g"/>
<feBlend in="SourceGraphic" in2="g"/>

The last matrix row is the trick: alpha × 20 − 9 turns a soft blur into a hard edge. Tailwind's only contribution is [filter:url(#tb-31-goo)] — and that is the right division, because an SVG filter is a document resource, not a style.

Two details make the illusion hold, and both are utilities: the bead matches the pill's cap exactly at rest, and both shapes paint the same gradient at the same bg-[length:…]. The goo threshold merges silhouettes, not tones — a lighter bead shows through as a disc behind the label.

Make it yours

  • Travel and size live in the hover pair: shorter throw + larger scale reads as thicker liquid.
  • Raise stdDeviation for a gloopier merge — the alpha multiplier must rise with it or edges soften.
  • Recolour with --color-tb31-hg; keep the highlight near-white or it stops looking metallic.
  • A second bead with a delay-* makes a chain of droplets.
  • The filter id is namespaced (tb-31-goo) — keep it that way if you paste two demos on one page.

Gotchas — read before shipping

  • Never apply the goo filter to an element containing text. feGaussianBlur blurs glyphs and thresholding cannot recover them.
  • SVG filters force a software raster pass on some GPUs. One instance is fine; twenty in a list is not.
  • The filter id must be unique per document — paint-server references are global.
  • filter creates a containing block and clips at the filter region. Give the wrapper room or the bead is cut off mid-flight.
  • A bead that hides at rest must match the shape it hides in — same size and same painted gradient, not merely the same colour.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

SVG filters via filter:url() work in all modern engines; feColorMatrix threshold rendering varies slightly between Blink, WebKit and Gecko — verify the exact values.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Search CodeFronts

Loading…