15 / 28
All 28 in 28 Tailwind CSS Close Buttons
- 01Tailwind Modal Close Button (Top-Right Corner X)
- 02Accessible Tailwind Close Button with Focus Ring (WCAG)
- 03iOS-Style Tailwind Tab Close Button
- 04Tailwind Floating Chat Widget Close Button
- 05Tailwind Cookie Consent Banner Dismiss Button
- 06Tailwind Mobile Ad Banner Close Button (48px Tap Target)
- 07Neumorphic Tailwind Close Button (Soft UI)
- 08Tailwind Hamburger to X Menu Button Animation
- 09Tailwind Video Player Overlay Close Button
- 10Tailwind Drawer Close Button with Native Dialog
- 11Origami Fold Tailwind Close Button
- 12Lock Tumbler Tailwind Close Button (@property)
- 13Rotate on Hover Tailwind Close Button
- 14Magnetic Cursor Tailwind Close Button
- 15Liquid Goo Tailwind Close Button (SVG Filter)
- 16Glitch Effect Tailwind Close Button
- 17Trash Compactor Tailwind Close Button
- 18Material Ripple Tailwind Close Button
- 19Particle Burst Tailwind Close Button
- 20Spring Snap Tailwind Close Button
- 21Neon Glow Tailwind Close Button
- 22Corner Ribbon Tailwind Close Button
- 233D Fold Away Tailwind Close Button
- 24Hold to Confirm Tailwind Close Button
- 25Tailwind Toast Notification Dismiss Button
- 26Tailwind Lightbox Image Close Button
- 27Brutalist Tailwind Close Button
- 28Galaxy Vortex Tailwind Close Button
Liquid Goo Tailwind Close Button (SVG Filter)
Metaballs in utilities: a blurred, re-thresholded SVG filter applied with [filter:url(#tcb15-goo)] fuses a main blob and two droplets into one liquid shape. Hover (or keyboard focus) flings the droplets out on a back-and-overshoot curve with group-hover/stack:translate-x-[38px], and the surface tension visibly snaps as they separate.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tcb-15 w-full min-h-svh grid place-items-center bg-[linear-gradient(170deg,var(--color-tcb15-bg),var(--color-tcb15-bg2))] px-6 py-12 font-tcb15-sans" aria-label="Liquid goo close button demo">
<svg class="absolute" width="0" height="0" aria-hidden="true"><defs><filter id="tcb15-goo"><feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/><feColorMatrix in="b" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="g"/><feComposite in="SourceGraphic" in2="g" operator="atop"/></filter></defs></svg>
<div class="grid w-full justify-items-center gap-7">
<div class="group/stack relative grid size-[130px] place-items-center">
<div aria-hidden="true" class="absolute inset-0 grid place-items-center [filter:url(#tcb15-goo)]">
<span class="absolute size-16 rounded-full bg-tcb15-goo"></span>
<span class="absolute size-5 rounded-full bg-tcb15-goo transition-[translate] duration-550 ease-[cubic-bezier(.68,-.55,.265,1.55)] group-hover/stack:translate-x-[38px] group-hover/stack:-translate-y-[27px] group-has-[:focus-visible]/stack:translate-x-[38px] group-has-[:focus-visible]/stack:-translate-y-[27px] motion-reduce:transition-none motion-reduce:translate-0!"></span>
<span class="absolute size-3.5 rounded-full bg-tcb15-goo transition-[translate] delay-40 duration-550 ease-[cubic-bezier(.68,-.55,.265,1.55)] group-hover/stack:-translate-x-[34px] group-hover/stack:translate-y-[30px] group-has-[:focus-visible]/stack:-translate-x-[34px] group-has-[:focus-visible]/stack:translate-y-[30px] motion-reduce:transition-none motion-reduce:translate-0!"></span>
</div>
<button type="button" aria-label="Close" class="relative grid size-16 cursor-pointer place-items-center rounded-full transition-[scale] duration-300 ease-[cubic-bezier(.34,1.56,.64,1)] hover:scale-106 focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-tcb15-ring active:scale-90 motion-reduce:transition-none">
<span aria-hidden="true" class="relative size-5.5 before:absolute before:top-1/2 before:left-1/2 before:h-[3px] before:w-5.5 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-white after:absolute after:top-1/2 after:left-1/2 after:h-[3px] after:w-5.5 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-white"></span>
</button>
</div>
<p aria-hidden="true" class="rounded-full bg-white/70 px-3.5 py-2 font-tcb15-mono text-[11.5px] text-tcb15-mut ring-1 ring-black/8">[filter:url(#tcb15-goo)] · group-hover/stack:translate-x-[38px]</p>
</div>
</section><section class="tcb-15 w-full min-h-svh grid place-items-center bg-[linear-gradient(170deg,var(--color-tcb15-bg),var(--color-tcb15-bg2))] px-6 py-12 font-tcb15-sans" aria-label="Liquid goo close button demo">
<svg class="absolute" width="0" height="0" aria-hidden="true"><defs><filter id="tcb15-goo"><feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/><feColorMatrix in="b" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="g"/><feComposite in="SourceGraphic" in2="g" operator="atop"/></filter></defs></svg>
<div class="grid w-full justify-items-center gap-7">
<div class="group/stack relative grid size-[130px] place-items-center">
<div aria-hidden="true" class="absolute inset-0 grid place-items-center [filter:url(#tcb15-goo)]">
<span class="absolute size-16 rounded-full bg-tcb15-goo"></span>
<span class="absolute size-5 rounded-full bg-tcb15-goo transition-[translate] duration-550 ease-[cubic-bezier(.68,-.55,.265,1.55)] group-hover/stack:translate-x-[38px] group-hover/stack:-translate-y-[27px] group-has-[:focus-visible]/stack:translate-x-[38px] group-has-[:focus-visible]/stack:-translate-y-[27px] motion-reduce:transition-none motion-reduce:translate-0!"></span>
<span class="absolute size-3.5 rounded-full bg-tcb15-goo transition-[translate] delay-40 duration-550 ease-[cubic-bezier(.68,-.55,.265,1.55)] group-hover/stack:-translate-x-[34px] group-hover/stack:translate-y-[30px] group-has-[:focus-visible]/stack:-translate-x-[34px] group-has-[:focus-visible]/stack:translate-y-[30px] motion-reduce:transition-none motion-reduce:translate-0!"></span>
</div>
<button type="button" aria-label="Close" class="relative grid size-16 cursor-pointer place-items-center rounded-full transition-[scale] duration-300 ease-[cubic-bezier(.34,1.56,.64,1)] hover:scale-106 focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-tcb15-ring active:scale-90 motion-reduce:transition-none">
<span aria-hidden="true" class="relative size-5.5 before:absolute before:top-1/2 before:left-1/2 before:h-[3px] before:w-5.5 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-white after:absolute after:top-1/2 after:left-1/2 after:h-[3px] after:w-5.5 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-white"></span>
</button>
</div>
<p aria-hidden="true" class="rounded-full bg-white/70 px-3.5 py-2 font-tcb15-mono text-[11.5px] text-tcb15-mut ring-1 ring-black/8">[filter:url(#tcb15-goo)] · group-hover/stack:translate-x-[38px]</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tcb15-bg: #fbf1f5;
--color-tcb15-bg: oklch(0.96 0.012 350);
--color-tcb15-bg2: #f3dde6;
--color-tcb15-bg2: oklch(0.92 0.03 340);
--color-tcb15-goo: #dd3d87;
--color-tcb15-goo: oklch(0.6 0.21 350);
--color-tcb15-ring: #a8155b;
--color-tcb15-ring: oklch(0.48 0.19 355);
--color-tcb15-mut: #7a4c60;
--color-tcb15-mut: oklch(0.47 0.07 350);
--font-tcb15-sans: 'Geist', system-ui, sans-serif;
--font-tcb15-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tcb-15 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tcb15-bg: #fbf1f5;
--color-tcb15-bg: oklch(0.96 0.012 350);
--color-tcb15-bg2: #f3dde6;
--color-tcb15-bg2: oklch(0.92 0.03 340);
--color-tcb15-goo: #dd3d87;
--color-tcb15-goo: oklch(0.6 0.21 350);
--color-tcb15-ring: #a8155b;
--color-tcb15-ring: oklch(0.48 0.19 355);
--color-tcb15-mut: #7a4c60;
--color-tcb15-mut: oklch(0.47 0.07 350);
--font-tcb15-sans: 'Geist', system-ui, sans-serif;
--font-tcb15-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tcb-15 {
width: 100%;
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-tcb15-bg: #fbf1f5;
--color-tcb15-bg: oklch(0.96 0.012 350);
--color-tcb15-bg2: #f3dde6;
--color-tcb15-bg2: oklch(0.92 0.03 340);
--color-tcb15-goo: #dd3d87;
--color-tcb15-goo: oklch(0.6 0.21 350);
--color-tcb15-ring: #a8155b;
--color-tcb15-ring: oklch(0.48 0.19 355);
--color-tcb15-mut: #7a4c60;
--color-tcb15-mut: oklch(0.47 0.07 350);
--font-tcb15-sans: 'Geist', system-ui, sans-serif;
--font-tcb15-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tcb-15 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tcb15-bg: #fbf1f5;
--color-tcb15-bg: oklch(0.96 0.012 350);
--color-tcb15-bg2: #f3dde6;
--color-tcb15-bg2: oklch(0.92 0.03 340);
--color-tcb15-goo: #dd3d87;
--color-tcb15-goo: oklch(0.6 0.21 350);
--color-tcb15-ring: #a8155b;
--color-tcb15-ring: oklch(0.48 0.19 355);
--color-tcb15-mut: #7a4c60;
--color-tcb15-mut: oklch(0.47 0.07 350);
--font-tcb15-sans: 'Geist', system-ui, sans-serif;
--font-tcb15-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tcb-15 {
width: 100%;
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=Geist:wght@400..800&family=Geist+Mono:wght@400..600&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=Geist:wght@400..800&family=Geist+Mono:wght@400..600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
translate(calc(var(--fling) * 1), calc(var(--fling) * -0.7))became literaltranslate-x-[38px] -translate-y-[27px]— the maths is done once, at authoring time.- UI upgrade from the CSS original: the goo darkened from
oklch(0.65)to0.6so the white × clears 4.5:1 on it, and the focus ring moved to a deeper ink that separates from the pink blob. - UI upgrade: keyboard focus now flings the droplets too (
group-has-[:focus-visible]/stack:), and reduced motion pins them withtranslate-0!.
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: Liquid Goo Tailwind Close Button (SVG Filter)
Source: https://codefronts.com/components/tailwind-css-close-buttons/liquid-pop/
Metaballs in utilities: a blurred, re-thresholded SVG filter applied with [filter:url(#tcb15-goo)] fuses a main blob and two droplets into one liquid shape. Hover (or keyboard focus) flings the droplets out on a back-and-overshoot curve with group-hover/stack:translate-x-[38px], and the surface tension visibly snaps as they separate.
## HTML
```html
<section class="tcb-15 w-full min-h-svh grid place-items-center bg-[linear-gradient(170deg,var(--color-tcb15-bg),var(--color-tcb15-bg2))] px-6 py-12 font-tcb15-sans" aria-label="Liquid goo close button demo">
<svg class="absolute" width="0" height="0" aria-hidden="true"><defs><filter id="tcb15-goo"><feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/><feColorMatrix in="b" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="g"/><feComposite in="SourceGraphic" in2="g" operator="atop"/></filter></defs></svg>
<div class="grid w-full justify-items-center gap-7">
<div class="group/stack relative grid size-[130px] place-items-center">
<div aria-hidden="true" class="absolute inset-0 grid place-items-center [filter:url(#tcb15-goo)]">
<span class="absolute size-16 rounded-full bg-tcb15-goo"></span>
<span class="absolute size-5 rounded-full bg-tcb15-goo transition-[translate] duration-550 ease-[cubic-bezier(.68,-.55,.265,1.55)] group-hover/stack:translate-x-[38px] group-hover/stack:-translate-y-[27px] group-has-[:focus-visible]/stack:translate-x-[38px] group-has-[:focus-visible]/stack:-translate-y-[27px] motion-reduce:transition-none motion-reduce:translate-0!"></span>
<span class="absolute size-3.5 rounded-full bg-tcb15-goo transition-[translate] delay-40 duration-550 ease-[cubic-bezier(.68,-.55,.265,1.55)] group-hover/stack:-translate-x-[34px] group-hover/stack:translate-y-[30px] group-has-[:focus-visible]/stack:-translate-x-[34px] group-has-[:focus-visible]/stack:translate-y-[30px] motion-reduce:transition-none motion-reduce:translate-0!"></span>
</div>
<button type="button" aria-label="Close" class="relative grid size-16 cursor-pointer place-items-center rounded-full transition-[scale] duration-300 ease-[cubic-bezier(.34,1.56,.64,1)] hover:scale-106 focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-tcb15-ring active:scale-90 motion-reduce:transition-none">
<span aria-hidden="true" class="relative size-5.5 before:absolute before:top-1/2 before:left-1/2 before:h-[3px] before:w-5.5 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-white after:absolute after:top-1/2 after:left-1/2 after:h-[3px] after:w-5.5 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-white"></span>
</button>
</div>
<p aria-hidden="true" class="rounded-full bg-white/70 px-3.5 py-2 font-tcb15-mono text-[11.5px] text-tcb15-mut ring-1 ring-black/8">[filter:url(#tcb15-goo)] · group-hover/stack:translate-x-[38px]</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcb15-bg: #fbf1f5;
--color-tcb15-bg: oklch(0.96 0.012 350);
--color-tcb15-bg2: #f3dde6;
--color-tcb15-bg2: oklch(0.92 0.03 340);
--color-tcb15-goo: #dd3d87;
--color-tcb15-goo: oklch(0.6 0.21 350);
--color-tcb15-ring: #a8155b;
--color-tcb15-ring: oklch(0.48 0.19 355);
--color-tcb15-mut: #7a4c60;
--color-tcb15-mut: oklch(0.47 0.07 350);
--font-tcb15-sans: 'Geist', system-ui, sans-serif;
--font-tcb15-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tcb-15 {
width: 100%;
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: Liquid Goo Tailwind Close Button (SVG Filter)
Source: https://codefronts.com/components/tailwind-css-close-buttons/liquid-pop/
Metaballs in utilities: a blurred, re-thresholded SVG filter applied with [filter:url(#tcb15-goo)] fuses a main blob and two droplets into one liquid shape. Hover (or keyboard focus) flings the droplets out on a back-and-overshoot curve with group-hover/stack:translate-x-[38px], and the surface tension visibly snaps as they separate.
## HTML
```html
<section class="tcb-15 w-full min-h-svh grid place-items-center bg-[linear-gradient(170deg,var(--color-tcb15-bg),var(--color-tcb15-bg2))] px-6 py-12 font-tcb15-sans" aria-label="Liquid goo close button demo">
<svg class="absolute" width="0" height="0" aria-hidden="true"><defs><filter id="tcb15-goo"><feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/><feColorMatrix in="b" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="g"/><feComposite in="SourceGraphic" in2="g" operator="atop"/></filter></defs></svg>
<div class="grid w-full justify-items-center gap-7">
<div class="group/stack relative grid size-[130px] place-items-center">
<div aria-hidden="true" class="absolute inset-0 grid place-items-center [filter:url(#tcb15-goo)]">
<span class="absolute size-16 rounded-full bg-tcb15-goo"></span>
<span class="absolute size-5 rounded-full bg-tcb15-goo transition-[translate] duration-550 ease-[cubic-bezier(.68,-.55,.265,1.55)] group-hover/stack:translate-x-[38px] group-hover/stack:-translate-y-[27px] group-has-[:focus-visible]/stack:translate-x-[38px] group-has-[:focus-visible]/stack:-translate-y-[27px] motion-reduce:transition-none motion-reduce:translate-0!"></span>
<span class="absolute size-3.5 rounded-full bg-tcb15-goo transition-[translate] delay-40 duration-550 ease-[cubic-bezier(.68,-.55,.265,1.55)] group-hover/stack:-translate-x-[34px] group-hover/stack:translate-y-[30px] group-has-[:focus-visible]/stack:-translate-x-[34px] group-has-[:focus-visible]/stack:translate-y-[30px] motion-reduce:transition-none motion-reduce:translate-0!"></span>
</div>
<button type="button" aria-label="Close" class="relative grid size-16 cursor-pointer place-items-center rounded-full transition-[scale] duration-300 ease-[cubic-bezier(.34,1.56,.64,1)] hover:scale-106 focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-tcb15-ring active:scale-90 motion-reduce:transition-none">
<span aria-hidden="true" class="relative size-5.5 before:absolute before:top-1/2 before:left-1/2 before:h-[3px] before:w-5.5 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-white after:absolute after:top-1/2 after:left-1/2 after:h-[3px] after:w-5.5 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-white"></span>
</button>
</div>
<p aria-hidden="true" class="rounded-full bg-white/70 px-3.5 py-2 font-tcb15-mono text-[11.5px] text-tcb15-mut ring-1 ring-black/8">[filter:url(#tcb15-goo)] · group-hover/stack:translate-x-[38px]</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcb15-bg: #fbf1f5;
--color-tcb15-bg: oklch(0.96 0.012 350);
--color-tcb15-bg2: #f3dde6;
--color-tcb15-bg2: oklch(0.92 0.03 340);
--color-tcb15-goo: #dd3d87;
--color-tcb15-goo: oklch(0.6 0.21 350);
--color-tcb15-ring: #a8155b;
--color-tcb15-ring: oklch(0.48 0.19 355);
--color-tcb15-mut: #7a4c60;
--color-tcb15-mut: oklch(0.47 0.07 350);
--font-tcb15-sans: 'Geist', system-ui, sans-serif;
--font-tcb15-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tcb-15 {
width: 100%;
min-height: 100svh;
}
```How this works
Blur + threshold = liquid. The filter blurs everything, then multiplies alpha by 18 and subtracts 7: soft overlaps become solid, soft edges become crisp. Two blobs near each other therefore read as one stretched droplet.
<div class="absolute inset-0 grid place-items-center [filter:url(#tcb15-goo)]">
<span class="size-4 … group-hover/stack:translate-x-[38px] group-hover/stack:-translate-y-[27px]">The button sits on top, unfiltered, so its × stays pin-sharp while the goo moves underneath.
Make it yours
- Stickier goo: raise
stdDeviationto 8 and the matrix to22 -9. - Farther fling: change the translate distances (the droplets are clipped by nothing, so the stage is the limit).
- Colour: edit
--color-tcb15-goo; the filter preserves it.
Gotchas — read before shipping
- SVG filter ids are document-global — keep them namespaced (
tcb15-goo) when several demos share a page. - Filters force a repaint every frame the droplets move; keep the filtered layer small.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
filter:url() on HTML is universal; the floor is Tailwind v4.