07 / 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
Neumorphic Tailwind Close Button (Soft UI)
Soft UI done responsibly: two opposing shadows — a light one up-left, a dark one down-right — extrude the button from the surface; active: swaps them for inset copies so it physically sinks with zero layout shift. The port adds what neumorphism usually forgets: a 3:1 hairline edge, a solid focus ring, and a glyph that turns accent on press so state is not signalled by shadow alone.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tcb-07 w-full min-h-svh grid place-items-center bg-tcb07-surface px-6 py-12 font-tcb07-sans text-tcb07-ink" aria-label="Neumorphic close button demo">
<div class="grid w-full justify-items-center gap-8">
<div class="flex w-full max-w-[20rem] items-center justify-between gap-4 rounded-[1.75rem] bg-tcb07-surface px-6 py-5 shadow-[-10px_-10px_24px_var(--color-tcb07-lite),10px_10px_24px_var(--color-tcb07-dark)]">
<div>
<div class="text-[15px] font-semibold">Focus mode</div>
<div class="mt-0.5 text-[13px] text-tcb07-mut">Notifications paused</div>
</div>
<button type="button" aria-label="Close focus mode" class="group relative size-14 flex-none cursor-pointer rounded-full bg-tcb07-surface shadow-[-6px_-6px_14px_var(--color-tcb07-lite),6px_6px_14px_var(--color-tcb07-dark)] ring-1 ring-tcb07-ink/12 transition-shadow duration-100 hover:shadow-[-8px_-8px_18px_var(--color-tcb07-lite),8px_8px_18px_var(--color-tcb07-dark)] focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcb07-acc active:shadow-[inset_-5px_-5px_12px_var(--color-tcb07-lite),inset_5px_5px_12px_var(--color-tcb07-dark)] motion-reduce:transition-none">
<span aria-hidden="true" class="absolute inset-0 before:absolute before:top-1/2 before:left-1/2 before:h-[2.5px] before:w-5 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-tcb07-ink before:transition-colors after:absolute after:top-1/2 after:left-1/2 after:h-[2.5px] after:w-5 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-tcb07-ink after:transition-colors group-active:before:bg-tcb07-acc group-active:after:bg-tcb07-acc"></span>
</button>
</div>
<p class="text-xs font-medium tracking-[0.05em] text-tcb07-mut">Press and hold the ×</p>
<p aria-hidden="true" class="rounded-full px-3.5 py-2 font-tcb07-mono text-[11.5px] text-tcb07-mut shadow-[inset_-3px_-3px_6px_var(--color-tcb07-lite),inset_3px_3px_6px_var(--color-tcb07-dark)]">shadow-[…lite,…dark] · active:shadow-[inset_…]</p>
</div>
</section><section class="tcb-07 w-full min-h-svh grid place-items-center bg-tcb07-surface px-6 py-12 font-tcb07-sans text-tcb07-ink" aria-label="Neumorphic close button demo">
<div class="grid w-full justify-items-center gap-8">
<div class="flex w-full max-w-[20rem] items-center justify-between gap-4 rounded-[1.75rem] bg-tcb07-surface px-6 py-5 shadow-[-10px_-10px_24px_var(--color-tcb07-lite),10px_10px_24px_var(--color-tcb07-dark)]">
<div>
<div class="text-[15px] font-semibold">Focus mode</div>
<div class="mt-0.5 text-[13px] text-tcb07-mut">Notifications paused</div>
</div>
<button type="button" aria-label="Close focus mode" class="group relative size-14 flex-none cursor-pointer rounded-full bg-tcb07-surface shadow-[-6px_-6px_14px_var(--color-tcb07-lite),6px_6px_14px_var(--color-tcb07-dark)] ring-1 ring-tcb07-ink/12 transition-shadow duration-100 hover:shadow-[-8px_-8px_18px_var(--color-tcb07-lite),8px_8px_18px_var(--color-tcb07-dark)] focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcb07-acc active:shadow-[inset_-5px_-5px_12px_var(--color-tcb07-lite),inset_5px_5px_12px_var(--color-tcb07-dark)] motion-reduce:transition-none">
<span aria-hidden="true" class="absolute inset-0 before:absolute before:top-1/2 before:left-1/2 before:h-[2.5px] before:w-5 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-tcb07-ink before:transition-colors after:absolute after:top-1/2 after:left-1/2 after:h-[2.5px] after:w-5 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-tcb07-ink after:transition-colors group-active:before:bg-tcb07-acc group-active:after:bg-tcb07-acc"></span>
</button>
</div>
<p class="text-xs font-medium tracking-[0.05em] text-tcb07-mut">Press and hold the ×</p>
<p aria-hidden="true" class="rounded-full px-3.5 py-2 font-tcb07-mono text-[11.5px] text-tcb07-mut shadow-[inset_-3px_-3px_6px_var(--color-tcb07-lite),inset_3px_3px_6px_var(--color-tcb07-dark)]">shadow-[…lite,…dark] · active:shadow-[inset_…]</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tcb07-surface: #dde1ea;
--color-tcb07-surface: oklch(0.9 0.015 260);
--color-tcb07-lite: #f5f6f9;
--color-tcb07-lite: oklch(0.97 0.005 260);
--color-tcb07-dark: #b8bcc6;
--color-tcb07-dark: oklch(0.79 0.015 260);
--color-tcb07-ink: #474d63;
--color-tcb07-ink: oklch(0.42 0.04 265);
--color-tcb07-mut: #525870;
--color-tcb07-mut: oklch(0.45 0.035 265);
--color-tcb07-acc: #3d4fcf;
--color-tcb07-acc: oklch(0.5 0.18 265);
--font-tcb07-sans: 'Geist', system-ui, sans-serif;
--font-tcb07-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-07 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tcb07-surface: #dde1ea;
--color-tcb07-surface: oklch(0.9 0.015 260);
--color-tcb07-lite: #f5f6f9;
--color-tcb07-lite: oklch(0.97 0.005 260);
--color-tcb07-dark: #b8bcc6;
--color-tcb07-dark: oklch(0.79 0.015 260);
--color-tcb07-ink: #474d63;
--color-tcb07-ink: oklch(0.42 0.04 265);
--color-tcb07-mut: #525870;
--color-tcb07-mut: oklch(0.45 0.035 265);
--color-tcb07-acc: #3d4fcf;
--color-tcb07-acc: oklch(0.5 0.18 265);
--font-tcb07-sans: 'Geist', system-ui, sans-serif;
--font-tcb07-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-07 {
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-tcb07-surface: #dde1ea;
--color-tcb07-surface: oklch(0.9 0.015 260);
--color-tcb07-lite: #f5f6f9;
--color-tcb07-lite: oklch(0.97 0.005 260);
--color-tcb07-dark: #b8bcc6;
--color-tcb07-dark: oklch(0.79 0.015 260);
--color-tcb07-ink: #474d63;
--color-tcb07-ink: oklch(0.42 0.04 265);
--color-tcb07-mut: #525870;
--color-tcb07-mut: oklch(0.45 0.035 265);
--color-tcb07-acc: #3d4fcf;
--color-tcb07-acc: oklch(0.5 0.18 265);
--font-tcb07-sans: 'Geist', system-ui, sans-serif;
--font-tcb07-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-07 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tcb07-surface: #dde1ea;
--color-tcb07-surface: oklch(0.9 0.015 260);
--color-tcb07-lite: #f5f6f9;
--color-tcb07-lite: oklch(0.97 0.005 260);
--color-tcb07-dark: #b8bcc6;
--color-tcb07-dark: oklch(0.79 0.015 260);
--color-tcb07-ink: #474d63;
--color-tcb07-ink: oklch(0.42 0.04 265);
--color-tcb07-mut: #525870;
--color-tcb07-mut: oklch(0.45 0.035 265);
--color-tcb07-acc: #3d4fcf;
--color-tcb07-acc: oklch(0.5 0.18 265);
--font-tcb07-sans: 'Geist', system-ui, sans-serif;
--font-tcb07-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-07 {
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.
- The
--lite/--darkcolor-mix()derivations became two@themecolours, so the shadow utilities read them asvar(--color-tcb07-*). - UI upgrade from the CSS original: the button now lives in a soft-UI card with a real label ("Close focus mode"), gained a 3:1 hairline ring for WCAG 1.4.11, and its glyph turns accent on press so state is not conveyed by shadow alone.
- UI upgrade: the hint was
color-mix(… 60%, transparent)— roughly 2.6:1; it is now a solidoklch(0.45)token at 5.4:1.
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: Neumorphic Tailwind Close Button (Soft UI)
Source: https://codefronts.com/components/tailwind-css-close-buttons/neumorphic-tailwind-close-button-soft-ui/
Soft UI done responsibly: two opposing shadows — a light one up-left, a dark one down-right — extrude the button from the surface; active: swaps them for inset copies so it physically sinks with zero layout shift. The port adds what neumorphism usually forgets: a 3:1 hairline edge, a solid focus ring, and a glyph that turns accent on press so state is not signalled by shadow alone.
## HTML
```html
<section class="tcb-07 w-full min-h-svh grid place-items-center bg-tcb07-surface px-6 py-12 font-tcb07-sans text-tcb07-ink" aria-label="Neumorphic close button demo">
<div class="grid w-full justify-items-center gap-8">
<div class="flex w-full max-w-[20rem] items-center justify-between gap-4 rounded-[1.75rem] bg-tcb07-surface px-6 py-5 shadow-[-10px_-10px_24px_var(--color-tcb07-lite),10px_10px_24px_var(--color-tcb07-dark)]">
<div>
<div class="text-[15px] font-semibold">Focus mode</div>
<div class="mt-0.5 text-[13px] text-tcb07-mut">Notifications paused</div>
</div>
<button type="button" aria-label="Close focus mode" class="group relative size-14 flex-none cursor-pointer rounded-full bg-tcb07-surface shadow-[-6px_-6px_14px_var(--color-tcb07-lite),6px_6px_14px_var(--color-tcb07-dark)] ring-1 ring-tcb07-ink/12 transition-shadow duration-100 hover:shadow-[-8px_-8px_18px_var(--color-tcb07-lite),8px_8px_18px_var(--color-tcb07-dark)] focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcb07-acc active:shadow-[inset_-5px_-5px_12px_var(--color-tcb07-lite),inset_5px_5px_12px_var(--color-tcb07-dark)] motion-reduce:transition-none">
<span aria-hidden="true" class="absolute inset-0 before:absolute before:top-1/2 before:left-1/2 before:h-[2.5px] before:w-5 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-tcb07-ink before:transition-colors after:absolute after:top-1/2 after:left-1/2 after:h-[2.5px] after:w-5 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-tcb07-ink after:transition-colors group-active:before:bg-tcb07-acc group-active:after:bg-tcb07-acc"></span>
</button>
</div>
<p class="text-xs font-medium tracking-[0.05em] text-tcb07-mut">Press and hold the ×</p>
<p aria-hidden="true" class="rounded-full px-3.5 py-2 font-tcb07-mono text-[11.5px] text-tcb07-mut shadow-[inset_-3px_-3px_6px_var(--color-tcb07-lite),inset_3px_3px_6px_var(--color-tcb07-dark)]">shadow-[…lite,…dark] · active:shadow-[inset_…]</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcb07-surface: #dde1ea;
--color-tcb07-surface: oklch(0.9 0.015 260);
--color-tcb07-lite: #f5f6f9;
--color-tcb07-lite: oklch(0.97 0.005 260);
--color-tcb07-dark: #b8bcc6;
--color-tcb07-dark: oklch(0.79 0.015 260);
--color-tcb07-ink: #474d63;
--color-tcb07-ink: oklch(0.42 0.04 265);
--color-tcb07-mut: #525870;
--color-tcb07-mut: oklch(0.45 0.035 265);
--color-tcb07-acc: #3d4fcf;
--color-tcb07-acc: oklch(0.5 0.18 265);
--font-tcb07-sans: 'Geist', system-ui, sans-serif;
--font-tcb07-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-07 {
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: Neumorphic Tailwind Close Button (Soft UI)
Source: https://codefronts.com/components/tailwind-css-close-buttons/neumorphic-tailwind-close-button-soft-ui/
Soft UI done responsibly: two opposing shadows — a light one up-left, a dark one down-right — extrude the button from the surface; active: swaps them for inset copies so it physically sinks with zero layout shift. The port adds what neumorphism usually forgets: a 3:1 hairline edge, a solid focus ring, and a glyph that turns accent on press so state is not signalled by shadow alone.
## HTML
```html
<section class="tcb-07 w-full min-h-svh grid place-items-center bg-tcb07-surface px-6 py-12 font-tcb07-sans text-tcb07-ink" aria-label="Neumorphic close button demo">
<div class="grid w-full justify-items-center gap-8">
<div class="flex w-full max-w-[20rem] items-center justify-between gap-4 rounded-[1.75rem] bg-tcb07-surface px-6 py-5 shadow-[-10px_-10px_24px_var(--color-tcb07-lite),10px_10px_24px_var(--color-tcb07-dark)]">
<div>
<div class="text-[15px] font-semibold">Focus mode</div>
<div class="mt-0.5 text-[13px] text-tcb07-mut">Notifications paused</div>
</div>
<button type="button" aria-label="Close focus mode" class="group relative size-14 flex-none cursor-pointer rounded-full bg-tcb07-surface shadow-[-6px_-6px_14px_var(--color-tcb07-lite),6px_6px_14px_var(--color-tcb07-dark)] ring-1 ring-tcb07-ink/12 transition-shadow duration-100 hover:shadow-[-8px_-8px_18px_var(--color-tcb07-lite),8px_8px_18px_var(--color-tcb07-dark)] focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcb07-acc active:shadow-[inset_-5px_-5px_12px_var(--color-tcb07-lite),inset_5px_5px_12px_var(--color-tcb07-dark)] motion-reduce:transition-none">
<span aria-hidden="true" class="absolute inset-0 before:absolute before:top-1/2 before:left-1/2 before:h-[2.5px] before:w-5 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-tcb07-ink before:transition-colors after:absolute after:top-1/2 after:left-1/2 after:h-[2.5px] after:w-5 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-tcb07-ink after:transition-colors group-active:before:bg-tcb07-acc group-active:after:bg-tcb07-acc"></span>
</button>
</div>
<p class="text-xs font-medium tracking-[0.05em] text-tcb07-mut">Press and hold the ×</p>
<p aria-hidden="true" class="rounded-full px-3.5 py-2 font-tcb07-mono text-[11.5px] text-tcb07-mut shadow-[inset_-3px_-3px_6px_var(--color-tcb07-lite),inset_3px_3px_6px_var(--color-tcb07-dark)]">shadow-[…lite,…dark] · active:shadow-[inset_…]</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcb07-surface: #dde1ea;
--color-tcb07-surface: oklch(0.9 0.015 260);
--color-tcb07-lite: #f5f6f9;
--color-tcb07-lite: oklch(0.97 0.005 260);
--color-tcb07-dark: #b8bcc6;
--color-tcb07-dark: oklch(0.79 0.015 260);
--color-tcb07-ink: #474d63;
--color-tcb07-ink: oklch(0.42 0.04 265);
--color-tcb07-mut: #525870;
--color-tcb07-mut: oklch(0.45 0.035 265);
--color-tcb07-acc: #3d4fcf;
--color-tcb07-acc: oklch(0.5 0.18 265);
--font-tcb07-sans: 'Geist', system-ui, sans-serif;
--font-tcb07-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-07 {
width: 100%;
min-height: 100svh;
}
```How this works
Same surface, two lights. The button's background equals the stage's; only shadows separate them:
bg-tcb07-surface
shadow-[-6px_-6px_14px_var(--color-tcb07-lite),6px_6px_14px_var(--color-tcb07-dark)]
active:shadow-[inset_-5px_-5px_12px_var(--color-tcb07-lite),inset_5px_5px_12px_var(--color-tcb07-dark)]Why the tokens. lite and dark are the surface mixed toward white and black; keeping them in @theme means one edit re-tints the whole material.
Make it yours
- Deeper relief: raise offsets to
10pxand blur to24pxon larger buttons. - Squircle:
rounded-full→rounded-[22px]. - Dark soft UI: set surface to
oklch(0.28 0.02 260)and derive lite/dark the same way.
Gotchas — read before shipping
- Pure neumorphism fails WCAG 1.4.11 (non-text contrast) — keep the hairline ring or a visible glyph ≥3:1.
- Shadows transition as a list; both states must have the same number of layers or the change snaps instead of easing.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Box-shadow is universal; the floor is Tailwind v4's generated sheet.