01 / 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
Tailwind Modal Close Button (Top-Right Corner X)
The canonical dialog dismiss, rebuilt in utilities: a quiet 44px circle pinned with absolute top-3 end-3, its × drawn by two before:/after: bars — no icon font, no SVG. Hover tints the circle with hover:bg-tcb01-acc/12 and stretches the bars with group-hover:before:scale-x-115; the dialog itself fades in with zero JS via starting:.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tcb-01 w-full min-h-svh grid place-items-center bg-tcb01-bg bg-[linear-gradient(160deg,var(--color-tcb01-bg),var(--color-tcb01-bg2))] px-6 py-12 font-tcb01-sans text-tcb01-ink" aria-label="Modal close button demo">
<div class="grid w-full justify-items-center gap-7">
<div role="dialog" aria-labelledby="tcb-01-title" aria-describedby="tcb-01-text" class="relative w-full max-w-[25rem] rounded-[1.25rem] bg-white px-7 pt-8 pb-7 shadow-[0_30px_70px_-30px_var(--color-tcb01-shadow)] ring-1 ring-tcb01-ink/5 transition duration-500 ease-out starting:translate-y-3 starting:opacity-0 motion-reduce:transition-none">
<button type="button" aria-label="Close dialog" class="group absolute top-3 end-3 grid size-11 cursor-pointer place-items-center rounded-full transition-colors duration-200 hover:bg-tcb01-acc/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-94 motion-reduce:transition-none">
<span aria-hidden="true" class="relative size-4 before:absolute before:top-1/2 before:left-1/2 before:h-0.5 before:w-4 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-tcb01-glyph before:transition before:duration-200 after:absolute after:top-1/2 after:left-1/2 after:h-0.5 after:w-4 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-tcb01-glyph after:transition after:duration-200 group-hover:before:scale-x-115 group-hover:before:bg-tcb01-acc group-hover:after:scale-x-115 group-hover:after:bg-tcb01-acc motion-reduce:before:transition-none motion-reduce:after:transition-none"></span>
</button>
<span aria-hidden="true" class="mb-5 grid size-11 place-items-center rounded-xl bg-tcb01-acc/10 text-tcb01-acc"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="m4 7 8 6 8-6"/></svg></span>
<h3 id="tcb-01-title" class="pe-10 text-xl font-semibold tracking-[-0.015em]">Confirm your email</h3>
<p id="tcb-01-text" class="mt-2 text-[15px]/[1.6] text-tcb01-mut text-pretty">We sent a verification link to your inbox. Click it to activate your account.</p>
<div class="mt-6 flex flex-wrap gap-2.5">
<button type="button" class="min-h-11 flex-1 cursor-pointer rounded-xl bg-tcb01-acc px-4 text-sm font-semibold text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-98">Open mail app</button>
<button type="button" class="min-h-11 flex-1 cursor-pointer rounded-xl px-4 text-sm font-semibold text-tcb01-ink ring-1 ring-tcb01-ink/12 transition hover:bg-tcb01-ink/4 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-98">Resend link</button>
</div>
</div>
<p aria-hidden="true" class="rounded-full bg-white/60 px-3.5 py-2 font-tcb01-mono text-[11.5px] text-tcb01-mut ring-1 ring-tcb01-ink/10">before:rotate-45 · group-hover:before:scale-x-115 · starting:opacity-0</p>
</div>
</section><section class="tcb-01 w-full min-h-svh grid place-items-center bg-tcb01-bg bg-[linear-gradient(160deg,var(--color-tcb01-bg),var(--color-tcb01-bg2))] px-6 py-12 font-tcb01-sans text-tcb01-ink" aria-label="Modal close button demo">
<div class="grid w-full justify-items-center gap-7">
<div role="dialog" aria-labelledby="tcb-01-title" aria-describedby="tcb-01-text" class="relative w-full max-w-[25rem] rounded-[1.25rem] bg-white px-7 pt-8 pb-7 shadow-[0_30px_70px_-30px_var(--color-tcb01-shadow)] ring-1 ring-tcb01-ink/5 transition duration-500 ease-out starting:translate-y-3 starting:opacity-0 motion-reduce:transition-none">
<button type="button" aria-label="Close dialog" class="group absolute top-3 end-3 grid size-11 cursor-pointer place-items-center rounded-full transition-colors duration-200 hover:bg-tcb01-acc/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-94 motion-reduce:transition-none">
<span aria-hidden="true" class="relative size-4 before:absolute before:top-1/2 before:left-1/2 before:h-0.5 before:w-4 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-tcb01-glyph before:transition before:duration-200 after:absolute after:top-1/2 after:left-1/2 after:h-0.5 after:w-4 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-tcb01-glyph after:transition after:duration-200 group-hover:before:scale-x-115 group-hover:before:bg-tcb01-acc group-hover:after:scale-x-115 group-hover:after:bg-tcb01-acc motion-reduce:before:transition-none motion-reduce:after:transition-none"></span>
</button>
<span aria-hidden="true" class="mb-5 grid size-11 place-items-center rounded-xl bg-tcb01-acc/10 text-tcb01-acc"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="m4 7 8 6 8-6"/></svg></span>
<h3 id="tcb-01-title" class="pe-10 text-xl font-semibold tracking-[-0.015em]">Confirm your email</h3>
<p id="tcb-01-text" class="mt-2 text-[15px]/[1.6] text-tcb01-mut text-pretty">We sent a verification link to your inbox. Click it to activate your account.</p>
<div class="mt-6 flex flex-wrap gap-2.5">
<button type="button" class="min-h-11 flex-1 cursor-pointer rounded-xl bg-tcb01-acc px-4 text-sm font-semibold text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-98">Open mail app</button>
<button type="button" class="min-h-11 flex-1 cursor-pointer rounded-xl px-4 text-sm font-semibold text-tcb01-ink ring-1 ring-tcb01-ink/12 transition hover:bg-tcb01-ink/4 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-98">Resend link</button>
</div>
</div>
<p aria-hidden="true" class="rounded-full bg-white/60 px-3.5 py-2 font-tcb01-mono text-[11.5px] text-tcb01-mut ring-1 ring-tcb01-ink/10">before:rotate-45 · group-hover:before:scale-x-115 · starting:opacity-0</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tcb01-bg: #eef0fa;
--color-tcb01-bg: oklch(0.95 0.015 265);
--color-tcb01-bg2: #dcdcf5;
--color-tcb01-bg2: oklch(0.9 0.03 280);
--color-tcb01-ink: #282a3a;
--color-tcb01-ink: oklch(0.27 0.025 270);
--color-tcb01-mut: #5c5f70;
--color-tcb01-mut: oklch(0.47 0.02 270);
--color-tcb01-glyph: #545766;
--color-tcb01-glyph: oklch(0.45 0.02 270);
--color-tcb01-acc: #4b5ccf;
--color-tcb01-acc: oklch(0.52 0.17 268);
--color-tcb01-shadow: #3a347080;
--color-tcb01-shadow: oklch(0.35 0.08 270 / 0.55);
--font-tcb01-sans: 'Geist', system-ui, sans-serif;
--font-tcb01-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-01 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tcb01-bg: #eef0fa;
--color-tcb01-bg: oklch(0.95 0.015 265);
--color-tcb01-bg2: #dcdcf5;
--color-tcb01-bg2: oklch(0.9 0.03 280);
--color-tcb01-ink: #282a3a;
--color-tcb01-ink: oklch(0.27 0.025 270);
--color-tcb01-mut: #5c5f70;
--color-tcb01-mut: oklch(0.47 0.02 270);
--color-tcb01-glyph: #545766;
--color-tcb01-glyph: oklch(0.45 0.02 270);
--color-tcb01-acc: #4b5ccf;
--color-tcb01-acc: oklch(0.52 0.17 268);
--color-tcb01-shadow: #3a347080;
--color-tcb01-shadow: oklch(0.35 0.08 270 / 0.55);
--font-tcb01-sans: 'Geist', system-ui, sans-serif;
--font-tcb01-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-01 {
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-tcb01-bg: #eef0fa;
--color-tcb01-bg: oklch(0.95 0.015 265);
--color-tcb01-bg2: #dcdcf5;
--color-tcb01-bg2: oklch(0.9 0.03 280);
--color-tcb01-ink: #282a3a;
--color-tcb01-ink: oklch(0.27 0.025 270);
--color-tcb01-mut: #5c5f70;
--color-tcb01-mut: oklch(0.47 0.02 270);
--color-tcb01-glyph: #545766;
--color-tcb01-glyph: oklch(0.45 0.02 270);
--color-tcb01-acc: #4b5ccf;
--color-tcb01-acc: oklch(0.52 0.17 268);
--color-tcb01-shadow: #3a347080;
--color-tcb01-shadow: oklch(0.35 0.08 270 / 0.55);
--font-tcb01-sans: 'Geist', system-ui, sans-serif;
--font-tcb01-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-01 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tcb01-bg: #eef0fa;
--color-tcb01-bg: oklch(0.95 0.015 265);
--color-tcb01-bg2: #dcdcf5;
--color-tcb01-bg2: oklch(0.9 0.03 280);
--color-tcb01-ink: #282a3a;
--color-tcb01-ink: oklch(0.27 0.025 270);
--color-tcb01-mut: #5c5f70;
--color-tcb01-mut: oklch(0.47 0.02 270);
--color-tcb01-glyph: #545766;
--color-tcb01-glyph: oklch(0.45 0.02 270);
--color-tcb01-acc: #4b5ccf;
--color-tcb01-acc: oklch(0.52 0.17 268);
--color-tcb01-shadow: #3a347080;
--color-tcb01-shadow: oklch(0.35 0.08 270 / 0.55);
--font-tcb01-sans: 'Geist', system-ui, sans-serif;
--font-tcb01-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-01 {
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 seven CSS rules that drew, positioned and animated the × collapsed into one class list on a glyph span; hover no longer restates the base transform because v4's individual transform properties compose on their own.
color-mix(in oklab, var(--accent) 12%, transparent)became the opacity modifierhover:bg-tcb01-acc/12.- UI upgrade from the CSS original: the button grew from 40px to 44px (WCAG 2.5.5 target), the dialog now enters with a
starting:fade-up, and it gained an icon plus a real primary/secondary action row so the × is no longer the only way out. - UI upgrade: body copy darkened from
oklch(0.5)to0.47(now 6.9:1), andaria-describedbylinks the text to the dialog.
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 Modal Close Button (Top-Right Corner X)
Source: https://codefronts.com/components/tailwind-css-close-buttons/tailwind-modal-close-button-top-right/
The canonical dialog dismiss, rebuilt in utilities: a quiet 44px circle pinned with absolute top-3 end-3, its × drawn by two before:/after: bars — no icon font, no SVG. Hover tints the circle with hover:bg-tcb01-acc/12 and stretches the bars with group-hover:before:scale-x-115; the dialog itself fades in with zero JS via starting:.
## HTML
```html
<section class="tcb-01 w-full min-h-svh grid place-items-center bg-tcb01-bg bg-[linear-gradient(160deg,var(--color-tcb01-bg),var(--color-tcb01-bg2))] px-6 py-12 font-tcb01-sans text-tcb01-ink" aria-label="Modal close button demo">
<div class="grid w-full justify-items-center gap-7">
<div role="dialog" aria-labelledby="tcb-01-title" aria-describedby="tcb-01-text" class="relative w-full max-w-[25rem] rounded-[1.25rem] bg-white px-7 pt-8 pb-7 shadow-[0_30px_70px_-30px_var(--color-tcb01-shadow)] ring-1 ring-tcb01-ink/5 transition duration-500 ease-out starting:translate-y-3 starting:opacity-0 motion-reduce:transition-none">
<button type="button" aria-label="Close dialog" class="group absolute top-3 end-3 grid size-11 cursor-pointer place-items-center rounded-full transition-colors duration-200 hover:bg-tcb01-acc/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-94 motion-reduce:transition-none">
<span aria-hidden="true" class="relative size-4 before:absolute before:top-1/2 before:left-1/2 before:h-0.5 before:w-4 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-tcb01-glyph before:transition before:duration-200 after:absolute after:top-1/2 after:left-1/2 after:h-0.5 after:w-4 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-tcb01-glyph after:transition after:duration-200 group-hover:before:scale-x-115 group-hover:before:bg-tcb01-acc group-hover:after:scale-x-115 group-hover:after:bg-tcb01-acc motion-reduce:before:transition-none motion-reduce:after:transition-none"></span>
</button>
<span aria-hidden="true" class="mb-5 grid size-11 place-items-center rounded-xl bg-tcb01-acc/10 text-tcb01-acc"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="m4 7 8 6 8-6"/></svg></span>
<h3 id="tcb-01-title" class="pe-10 text-xl font-semibold tracking-[-0.015em]">Confirm your email</h3>
<p id="tcb-01-text" class="mt-2 text-[15px]/[1.6] text-tcb01-mut text-pretty">We sent a verification link to your inbox. Click it to activate your account.</p>
<div class="mt-6 flex flex-wrap gap-2.5">
<button type="button" class="min-h-11 flex-1 cursor-pointer rounded-xl bg-tcb01-acc px-4 text-sm font-semibold text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-98">Open mail app</button>
<button type="button" class="min-h-11 flex-1 cursor-pointer rounded-xl px-4 text-sm font-semibold text-tcb01-ink ring-1 ring-tcb01-ink/12 transition hover:bg-tcb01-ink/4 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-98">Resend link</button>
</div>
</div>
<p aria-hidden="true" class="rounded-full bg-white/60 px-3.5 py-2 font-tcb01-mono text-[11.5px] text-tcb01-mut ring-1 ring-tcb01-ink/10">before:rotate-45 · group-hover:before:scale-x-115 · starting:opacity-0</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcb01-bg: #eef0fa;
--color-tcb01-bg: oklch(0.95 0.015 265);
--color-tcb01-bg2: #dcdcf5;
--color-tcb01-bg2: oklch(0.9 0.03 280);
--color-tcb01-ink: #282a3a;
--color-tcb01-ink: oklch(0.27 0.025 270);
--color-tcb01-mut: #5c5f70;
--color-tcb01-mut: oklch(0.47 0.02 270);
--color-tcb01-glyph: #545766;
--color-tcb01-glyph: oklch(0.45 0.02 270);
--color-tcb01-acc: #4b5ccf;
--color-tcb01-acc: oklch(0.52 0.17 268);
--color-tcb01-shadow: #3a347080;
--color-tcb01-shadow: oklch(0.35 0.08 270 / 0.55);
--font-tcb01-sans: 'Geist', system-ui, sans-serif;
--font-tcb01-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-01 {
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: Tailwind Modal Close Button (Top-Right Corner X)
Source: https://codefronts.com/components/tailwind-css-close-buttons/tailwind-modal-close-button-top-right/
The canonical dialog dismiss, rebuilt in utilities: a quiet 44px circle pinned with absolute top-3 end-3, its × drawn by two before:/after: bars — no icon font, no SVG. Hover tints the circle with hover:bg-tcb01-acc/12 and stretches the bars with group-hover:before:scale-x-115; the dialog itself fades in with zero JS via starting:.
## HTML
```html
<section class="tcb-01 w-full min-h-svh grid place-items-center bg-tcb01-bg bg-[linear-gradient(160deg,var(--color-tcb01-bg),var(--color-tcb01-bg2))] px-6 py-12 font-tcb01-sans text-tcb01-ink" aria-label="Modal close button demo">
<div class="grid w-full justify-items-center gap-7">
<div role="dialog" aria-labelledby="tcb-01-title" aria-describedby="tcb-01-text" class="relative w-full max-w-[25rem] rounded-[1.25rem] bg-white px-7 pt-8 pb-7 shadow-[0_30px_70px_-30px_var(--color-tcb01-shadow)] ring-1 ring-tcb01-ink/5 transition duration-500 ease-out starting:translate-y-3 starting:opacity-0 motion-reduce:transition-none">
<button type="button" aria-label="Close dialog" class="group absolute top-3 end-3 grid size-11 cursor-pointer place-items-center rounded-full transition-colors duration-200 hover:bg-tcb01-acc/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-94 motion-reduce:transition-none">
<span aria-hidden="true" class="relative size-4 before:absolute before:top-1/2 before:left-1/2 before:h-0.5 before:w-4 before:-translate-1/2 before:rotate-45 before:rounded-full before:bg-tcb01-glyph before:transition before:duration-200 after:absolute after:top-1/2 after:left-1/2 after:h-0.5 after:w-4 after:-translate-1/2 after:-rotate-45 after:rounded-full after:bg-tcb01-glyph after:transition after:duration-200 group-hover:before:scale-x-115 group-hover:before:bg-tcb01-acc group-hover:after:scale-x-115 group-hover:after:bg-tcb01-acc motion-reduce:before:transition-none motion-reduce:after:transition-none"></span>
</button>
<span aria-hidden="true" class="mb-5 grid size-11 place-items-center rounded-xl bg-tcb01-acc/10 text-tcb01-acc"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="m4 7 8 6 8-6"/></svg></span>
<h3 id="tcb-01-title" class="pe-10 text-xl font-semibold tracking-[-0.015em]">Confirm your email</h3>
<p id="tcb-01-text" class="mt-2 text-[15px]/[1.6] text-tcb01-mut text-pretty">We sent a verification link to your inbox. Click it to activate your account.</p>
<div class="mt-6 flex flex-wrap gap-2.5">
<button type="button" class="min-h-11 flex-1 cursor-pointer rounded-xl bg-tcb01-acc px-4 text-sm font-semibold text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-98">Open mail app</button>
<button type="button" class="min-h-11 flex-1 cursor-pointer rounded-xl px-4 text-sm font-semibold text-tcb01-ink ring-1 ring-tcb01-ink/12 transition hover:bg-tcb01-ink/4 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcb01-acc active:scale-98">Resend link</button>
</div>
</div>
<p aria-hidden="true" class="rounded-full bg-white/60 px-3.5 py-2 font-tcb01-mono text-[11.5px] text-tcb01-mut ring-1 ring-tcb01-ink/10">before:rotate-45 · group-hover:before:scale-x-115 · starting:opacity-0</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcb01-bg: #eef0fa;
--color-tcb01-bg: oklch(0.95 0.015 265);
--color-tcb01-bg2: #dcdcf5;
--color-tcb01-bg2: oklch(0.9 0.03 280);
--color-tcb01-ink: #282a3a;
--color-tcb01-ink: oklch(0.27 0.025 270);
--color-tcb01-mut: #5c5f70;
--color-tcb01-mut: oklch(0.47 0.02 270);
--color-tcb01-glyph: #545766;
--color-tcb01-glyph: oklch(0.45 0.02 270);
--color-tcb01-acc: #4b5ccf;
--color-tcb01-acc: oklch(0.52 0.17 268);
--color-tcb01-shadow: #3a347080;
--color-tcb01-shadow: oklch(0.35 0.08 270 / 0.55);
--font-tcb01-sans: 'Geist', system-ui, sans-serif;
--font-tcb01-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-01 {
width: 100%;
min-height: 100svh;
}
```How this works
The × is two pseudo-element bars, declared where they render. The glyph span carries both bars; each is centred with top-1/2 left-1/2 -translate-1/2 and turned with rotate-45 / -rotate-45:
<span class="relative size-4
before:absolute before:top-1/2 before:left-1/2 before:h-0.5 before:w-4
before:-translate-1/2 before:rotate-45 before:bg-tcb01-glyph
after:… after:-rotate-45">Why the order is free. Tailwind v4 writes translate, rotate and scale as separate CSS properties, which the browser always applies translate → rotate → scale. The CSS original had to repeat translate(-50%,-50%) rotate(45deg) in every hover rule; here hover only adds scale-x-115.
Make it yours
- Offset: change
top-3 end-3totop-4 end-4for roomier dialogs — the 44px hit area stays intact. - Glyph weight: swap
before:h-0.5 after:h-0.5forh-[2.5px]for a bolder ×. - Re-theme: edit
--color-tcb01-accin@theme; hover tint, glyph and focus ring all follow.
Gotchas — read before shipping
before:utilities emitcontent: var(--tw-content)automatically — you do not needbefore:content-['']for an empty bar.- Put the button first inside the dialog if you want it to be the first focus stop; put it last if the primary action should be.
starting:only animates first render; it does not replay when you toggledisplayunless the transition includestransition-discrete.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 117+ | 17.5+ | 129+ | 117+ |
The floor is Tailwind v4 (Chrome 111 / Safari 16.4 / Firefox 128); starting: needs @starting-style and simply skips the fade on older engines.