14 / 20
All 20 in 20 Tailwind CSS Claymorphism
- 01Tailwind CSS Claymorphism Box Shadow Recipe (3-Layer Formula)
- 02Tailwind Inner Shadow & Inset Highlight for Clay UI
- 03Tailwind Border Radius Scale & Squircle Corners for Puffy Shapes
- 04Claymorphism vs Neumorphism in Tailwind CSS (Side-by-Side)
- 05Tailwind Glassmorphism + Claymorphism Hybrid Card
- 06Tailwind Clay UI Light Source & Shadow Direction System
- 07Tailwind Elevation Shadow Scale: Clay Depth Tiers
- 08Tailwind CSS v4 Claymorphism: @theme Tokens, @utility & Arbitrary Values
- 09Tailwind 3D Clay Button with Press & Squish Animation
- 10Tailwind Toggle Switch, Checkbox & Segmented Control (Clay Style)
- 11Tailwind Search Bar & Floating Label Input (Clay Inset Style)
- 12Tailwind Badge & Pill Tag Components (Clay Style)
- 13Tailwind Claymorphism Card Component (Container Query Responsive)
- 14Tailwind Modal Dialog with Popover API (Clay Floating Depth)
- 15Tailwind Pricing Table with Monthly/Yearly Toggle (Clay Style)
- 16Tailwind Mobile Bottom Navigation Bar (Clay Tab Bar)
- 17Tailwind App Icon Grid with 3D Hover Tilt (Clay Tiles)
- 18Tailwind Toast Notification & Alert Components (Clay Style)
- 19Tailwind Dark Mode Claymorphism: Shadow Recalibration with light-dark()
- 20Tailwind Animation Performance: GPU Transform vs Box-Shadow (Live FPS Meter)
Tailwind Modal Dialog with Popover API (Clay Floating Depth)
A tier-4 clay dialog on the native popover API — no focus-trap library, no script. The browser owns the top layer, light dismiss, Escape and focus return; Tailwind owns the rest: open:grid, starting:open:scale-94 for the entry, transition-discrete for the exit, and backdrop:backdrop-blur-[7px] for the scrim. New: a labelled close button and drawn check glyphs in the checklist.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tcl-14 w-full min-h-svh grid place-items-center bg-tcl14-bg bg-[radial-gradient(85%_60%_at_50%_0%,var(--color-tcl14-glow),transparent_68%)] px-5 py-14 font-tcl14-sans text-tcl14-ink" aria-label="Clay modal dialog with floating depth demo">
<div class="grid w-full justify-items-center gap-5">
<div class="grid w-full max-w-[640px] justify-items-center gap-3.5 rounded-[44px] bg-tcl14-page p-[clamp(26px,4vw,46px)] text-center shadow-tcl14-page">
<h2 class="font-tcl14-display text-[clamp(26px,3.8vw,36px)] font-extrabold leading-[1.08] tracking-[-0.03em] text-balance">Native popover, clay depth</h2>
<p class="max-w-[48ch] text-[15px] leading-relaxed text-tcl14-mut text-pretty">The top layer, light dismiss, Escape and focus are the browser's job. Tier-4 shadows and a blurred backdrop are ours.</p>
<button type="button" popovertarget="tcl-14-dialog" class="mt-1.5 min-h-[58px] cursor-pointer rounded-[26px] bg-tcl14-accent px-8.5 text-base font-bold text-tcl14-accentink shadow-tcl14-cta transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-1 active:translate-y-0.75 active:scale-y-93 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-tcl14-ink">Publish collection</button>
<ul class="mt-1.5 flex flex-wrap justify-center gap-2" aria-label="Techniques">
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">popover="auto"</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">starting:open:</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">transition-discrete</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">backdrop:backdrop-blur</li>
</ul>
</div>
<div id="tcl-14-dialog" popover="auto" aria-labelledby="tcl-14-title" class="fixed inset-0 m-auto max-h-[86svh] w-[min(92vw,460px)] translate-y-3 scale-94 gap-3.5 overflow-auto rounded-[40px] border-0 bg-tcl14-clay p-[clamp(24px,3.6vw,34px)] text-tcl14-ink opacity-0 shadow-tcl14-modal transition-[opacity,scale,translate,display,overlay] transition-discrete duration-300 ease-[cubic-bezier(.2,.9,.3,1.15)] open:grid open:translate-y-0 open:scale-100 open:opacity-100 starting:open:translate-y-3 starting:open:scale-94 starting:open:opacity-0 backdrop:bg-tcl14-scrim backdrop:opacity-0 backdrop:backdrop-blur-[7px] backdrop:transition-[opacity,display,overlay] backdrop:transition-discrete backdrop:duration-300 open:backdrop:opacity-100 starting:open:backdrop:opacity-0 motion-reduce:transition-none">
<div class="flex items-center justify-between">
<span aria-hidden="true" class="w-11"></span>
<span aria-hidden="true" class="h-1.5 w-13.5 rounded-full bg-tcl14-shade/40 shadow-[inset_0_2px_3px_-1px_var(--color-tcl14-shade)]"></span>
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" aria-label="Close" class="grid size-11 cursor-pointer place-items-center rounded-full bg-tcl14-soft text-tcl14-ink shadow-tcl14-ghost transition-[translate] hover:-translate-y-0.5 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tcl14-ink"><svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8"/></svg></button>
</div>
<h3 id="tcl-14-title" class="font-tcl14-display text-[clamp(21px,3vw,25px)] font-extrabold tracking-[-0.025em] text-balance">Publish “20 Tailwind Claymorphism”?</h3>
<p class="text-[14.5px] leading-relaxed text-tcl14-ink/85 text-pretty">All 20 demos become public and the collection page goes live at once. You can unpublish any single demo later.</p>
<ul class="mt-0.5 mb-1 grid gap-2">
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Snippets validated</li>
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Reduced-motion pass</li>
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Contrast pass</li>
</ul>
<div class="mt-1 flex flex-wrap gap-2.5">
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" class="min-h-13 min-w-[130px] flex-1 cursor-pointer rounded-3xl bg-tcl14-soft px-5.5 text-[14.5px] font-bold text-tcl14-ink shadow-tcl14-ghost transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-0.75 active:translate-y-0.75 active:scale-y-94 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcl14-ink">Not yet</button>
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" class="min-h-13 min-w-[130px] flex-1 cursor-pointer rounded-3xl bg-tcl14-accent px-5.5 text-[14.5px] font-bold text-tcl14-accentink shadow-tcl14-cta transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-0.75 active:translate-y-0.75 active:scale-y-94 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcl14-ink">Publish now</button>
</div>
</div>
<p aria-hidden="true" class="rounded-full bg-white/55 px-4 py-2 text-center font-tcl14-mono text-[11.5px] text-tcl14-mut">tier-4 elevation · open: + starting:open: · transition-discrete · native top layer</p>
</div>
</section><section class="tcl-14 w-full min-h-svh grid place-items-center bg-tcl14-bg bg-[radial-gradient(85%_60%_at_50%_0%,var(--color-tcl14-glow),transparent_68%)] px-5 py-14 font-tcl14-sans text-tcl14-ink" aria-label="Clay modal dialog with floating depth demo">
<div class="grid w-full justify-items-center gap-5">
<div class="grid w-full max-w-[640px] justify-items-center gap-3.5 rounded-[44px] bg-tcl14-page p-[clamp(26px,4vw,46px)] text-center shadow-tcl14-page">
<h2 class="font-tcl14-display text-[clamp(26px,3.8vw,36px)] font-extrabold leading-[1.08] tracking-[-0.03em] text-balance">Native popover, clay depth</h2>
<p class="max-w-[48ch] text-[15px] leading-relaxed text-tcl14-mut text-pretty">The top layer, light dismiss, Escape and focus are the browser's job. Tier-4 shadows and a blurred backdrop are ours.</p>
<button type="button" popovertarget="tcl-14-dialog" class="mt-1.5 min-h-[58px] cursor-pointer rounded-[26px] bg-tcl14-accent px-8.5 text-base font-bold text-tcl14-accentink shadow-tcl14-cta transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-1 active:translate-y-0.75 active:scale-y-93 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-tcl14-ink">Publish collection</button>
<ul class="mt-1.5 flex flex-wrap justify-center gap-2" aria-label="Techniques">
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">popover="auto"</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">starting:open:</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">transition-discrete</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">backdrop:backdrop-blur</li>
</ul>
</div>
<div id="tcl-14-dialog" popover="auto" aria-labelledby="tcl-14-title" class="fixed inset-0 m-auto max-h-[86svh] w-[min(92vw,460px)] translate-y-3 scale-94 gap-3.5 overflow-auto rounded-[40px] border-0 bg-tcl14-clay p-[clamp(24px,3.6vw,34px)] text-tcl14-ink opacity-0 shadow-tcl14-modal transition-[opacity,scale,translate,display,overlay] transition-discrete duration-300 ease-[cubic-bezier(.2,.9,.3,1.15)] open:grid open:translate-y-0 open:scale-100 open:opacity-100 starting:open:translate-y-3 starting:open:scale-94 starting:open:opacity-0 backdrop:bg-tcl14-scrim backdrop:opacity-0 backdrop:backdrop-blur-[7px] backdrop:transition-[opacity,display,overlay] backdrop:transition-discrete backdrop:duration-300 open:backdrop:opacity-100 starting:open:backdrop:opacity-0 motion-reduce:transition-none">
<div class="flex items-center justify-between">
<span aria-hidden="true" class="w-11"></span>
<span aria-hidden="true" class="h-1.5 w-13.5 rounded-full bg-tcl14-shade/40 shadow-[inset_0_2px_3px_-1px_var(--color-tcl14-shade)]"></span>
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" aria-label="Close" class="grid size-11 cursor-pointer place-items-center rounded-full bg-tcl14-soft text-tcl14-ink shadow-tcl14-ghost transition-[translate] hover:-translate-y-0.5 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tcl14-ink"><svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8"/></svg></button>
</div>
<h3 id="tcl-14-title" class="font-tcl14-display text-[clamp(21px,3vw,25px)] font-extrabold tracking-[-0.025em] text-balance">Publish “20 Tailwind Claymorphism”?</h3>
<p class="text-[14.5px] leading-relaxed text-tcl14-ink/85 text-pretty">All 20 demos become public and the collection page goes live at once. You can unpublish any single demo later.</p>
<ul class="mt-0.5 mb-1 grid gap-2">
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Snippets validated</li>
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Reduced-motion pass</li>
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Contrast pass</li>
</ul>
<div class="mt-1 flex flex-wrap gap-2.5">
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" class="min-h-13 min-w-[130px] flex-1 cursor-pointer rounded-3xl bg-tcl14-soft px-5.5 text-[14.5px] font-bold text-tcl14-ink shadow-tcl14-ghost transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-0.75 active:translate-y-0.75 active:scale-y-94 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcl14-ink">Not yet</button>
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" class="min-h-13 min-w-[130px] flex-1 cursor-pointer rounded-3xl bg-tcl14-accent px-5.5 text-[14.5px] font-bold text-tcl14-accentink shadow-tcl14-cta transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-0.75 active:translate-y-0.75 active:scale-y-94 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcl14-ink">Publish now</button>
</div>
</div>
<p aria-hidden="true" class="rounded-full bg-white/55 px-4 py-2 text-center font-tcl14-mono text-[11.5px] text-tcl14-mut">tier-4 elevation · open: + starting:open: · transition-discrete · native top layer</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tcl14-bg: #ebe3fc;
--color-tcl14-bg: oklch(0.93 0.035 300);
--color-tcl14-glow: #fcefff;
--color-tcl14-glow: oklch(0.97 0.035 310);
--color-tcl14-page: #f2edfd;
--color-tcl14-page: oklch(0.955 0.022 300);
--color-tcl14-clay: #e3d7fb;
--color-tcl14-clay: oklch(0.9 0.05 300);
--color-tcl14-soft: #eee7ff;
--color-tcl14-soft: oklch(0.94 0.034 300);
--color-tcl14-accent: #c9a5ff;
--color-tcl14-accent: oklch(0.79 0.14 300);
--color-tcl14-accentink: #26133f;
--color-tcl14-accentink: oklch(0.24 0.08 300);
--color-tcl14-ok: #00884b;
--color-tcl14-ok: oklch(0.55 0.14 155);
--color-tcl14-scrim: #3d30526b;
--color-tcl14-scrim: oklch(0.34 0.06 300 / 0.42);
--color-tcl14-shade: #6c55948c;
--color-tcl14-shade: oklch(0.5 0.1 300 / 0.55);
--color-tcl14-light: #fffdfff2;
--color-tcl14-light: oklch(1 0.012 300 / 0.95);
--color-tcl14-ink: #291c3c;
--color-tcl14-ink: oklch(0.26 0.06 300);
--color-tcl14-mut: #594f6d;
--color-tcl14-mut: oklch(0.45 0.05 300);
--font-tcl14-display: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tcl14-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tcl14-mono: 'JetBrains Mono', ui-monospace, monospace;
--shadow-tcl14-page: 0 26px 48px -20px var(--color-tcl14-shade), inset 0 -16px 28px -16px var(--color-tcl14-shade), inset 0 18px 28px -12px var(--color-tcl14-light);
--shadow-tcl14-modal: 0 60px 110px -30px oklch(0.32 0.08 300 / 0.65), 0 24px 44px -16px var(--color-tcl14-shade), inset 0 -20px 34px -16px var(--color-tcl14-shade), inset 0 24px 34px -10px var(--color-tcl14-light);
--shadow-tcl14-cta: 0 16px 28px -12px var(--color-tcl14-shade), inset 0 -12px 20px -9px var(--color-tcl14-shade), inset 0 14px 20px -7px var(--color-tcl14-light);
--shadow-tcl14-ghost: 0 12px 20px -12px var(--color-tcl14-shade), inset 0 -9px 15px -9px var(--color-tcl14-shade), inset 0 11px 15px -7px var(--color-tcl14-light);
--shadow-tcl14-press: 0 0 0 0 transparent, inset 0 12px 18px -8px var(--color-tcl14-shade), inset 0 -6px 12px -9px var(--color-tcl14-light);
--shadow-tcl14-row: inset 0 -6px 11px -8px var(--color-tcl14-shade), inset 0 7px 11px -6px var(--color-tcl14-light);
--shadow-tcl14-fact: inset 0 -4px 8px -7px var(--color-tcl14-shade), inset 0 5px 8px -5px white;
--shadow-tcl14-tick: inset 0 5px 7px -4px oklch(1 0 0 / 0.6), 0 4px 7px -4px var(--color-tcl14-shade);
}
/* 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. */
.tcl-14 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tcl14-bg: #ebe3fc;
--color-tcl14-bg: oklch(0.93 0.035 300);
--color-tcl14-glow: #fcefff;
--color-tcl14-glow: oklch(0.97 0.035 310);
--color-tcl14-page: #f2edfd;
--color-tcl14-page: oklch(0.955 0.022 300);
--color-tcl14-clay: #e3d7fb;
--color-tcl14-clay: oklch(0.9 0.05 300);
--color-tcl14-soft: #eee7ff;
--color-tcl14-soft: oklch(0.94 0.034 300);
--color-tcl14-accent: #c9a5ff;
--color-tcl14-accent: oklch(0.79 0.14 300);
--color-tcl14-accentink: #26133f;
--color-tcl14-accentink: oklch(0.24 0.08 300);
--color-tcl14-ok: #00884b;
--color-tcl14-ok: oklch(0.55 0.14 155);
--color-tcl14-scrim: #3d30526b;
--color-tcl14-scrim: oklch(0.34 0.06 300 / 0.42);
--color-tcl14-shade: #6c55948c;
--color-tcl14-shade: oklch(0.5 0.1 300 / 0.55);
--color-tcl14-light: #fffdfff2;
--color-tcl14-light: oklch(1 0.012 300 / 0.95);
--color-tcl14-ink: #291c3c;
--color-tcl14-ink: oklch(0.26 0.06 300);
--color-tcl14-mut: #594f6d;
--color-tcl14-mut: oklch(0.45 0.05 300);
--font-tcl14-display: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tcl14-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tcl14-mono: 'JetBrains Mono', ui-monospace, monospace;
--shadow-tcl14-page: 0 26px 48px -20px var(--color-tcl14-shade), inset 0 -16px 28px -16px var(--color-tcl14-shade), inset 0 18px 28px -12px var(--color-tcl14-light);
--shadow-tcl14-modal: 0 60px 110px -30px oklch(0.32 0.08 300 / 0.65), 0 24px 44px -16px var(--color-tcl14-shade), inset 0 -20px 34px -16px var(--color-tcl14-shade), inset 0 24px 34px -10px var(--color-tcl14-light);
--shadow-tcl14-cta: 0 16px 28px -12px var(--color-tcl14-shade), inset 0 -12px 20px -9px var(--color-tcl14-shade), inset 0 14px 20px -7px var(--color-tcl14-light);
--shadow-tcl14-ghost: 0 12px 20px -12px var(--color-tcl14-shade), inset 0 -9px 15px -9px var(--color-tcl14-shade), inset 0 11px 15px -7px var(--color-tcl14-light);
--shadow-tcl14-press: 0 0 0 0 transparent, inset 0 12px 18px -8px var(--color-tcl14-shade), inset 0 -6px 12px -9px var(--color-tcl14-light);
--shadow-tcl14-row: inset 0 -6px 11px -8px var(--color-tcl14-shade), inset 0 7px 11px -6px var(--color-tcl14-light);
--shadow-tcl14-fact: inset 0 -4px 8px -7px var(--color-tcl14-shade), inset 0 5px 8px -5px white;
--shadow-tcl14-tick: inset 0 5px 7px -4px oklch(1 0 0 / 0.6), 0 4px 7px -4px var(--color-tcl14-shade);
}
/* 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. */
.tcl-14 {
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-tcl14-bg: #ebe3fc;
--color-tcl14-bg: oklch(0.93 0.035 300);
--color-tcl14-glow: #fcefff;
--color-tcl14-glow: oklch(0.97 0.035 310);
--color-tcl14-page: #f2edfd;
--color-tcl14-page: oklch(0.955 0.022 300);
--color-tcl14-clay: #e3d7fb;
--color-tcl14-clay: oklch(0.9 0.05 300);
--color-tcl14-soft: #eee7ff;
--color-tcl14-soft: oklch(0.94 0.034 300);
--color-tcl14-accent: #c9a5ff;
--color-tcl14-accent: oklch(0.79 0.14 300);
--color-tcl14-accentink: #26133f;
--color-tcl14-accentink: oklch(0.24 0.08 300);
--color-tcl14-ok: #00884b;
--color-tcl14-ok: oklch(0.55 0.14 155);
--color-tcl14-scrim: #3d30526b;
--color-tcl14-scrim: oklch(0.34 0.06 300 / 0.42);
--color-tcl14-shade: #6c55948c;
--color-tcl14-shade: oklch(0.5 0.1 300 / 0.55);
--color-tcl14-light: #fffdfff2;
--color-tcl14-light: oklch(1 0.012 300 / 0.95);
--color-tcl14-ink: #291c3c;
--color-tcl14-ink: oklch(0.26 0.06 300);
--color-tcl14-mut: #594f6d;
--color-tcl14-mut: oklch(0.45 0.05 300);
--font-tcl14-display: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tcl14-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tcl14-mono: 'JetBrains Mono', ui-monospace, monospace;
--shadow-tcl14-page: 0 26px 48px -20px var(--color-tcl14-shade), inset 0 -16px 28px -16px var(--color-tcl14-shade), inset 0 18px 28px -12px var(--color-tcl14-light);
--shadow-tcl14-modal: 0 60px 110px -30px oklch(0.32 0.08 300 / 0.65), 0 24px 44px -16px var(--color-tcl14-shade), inset 0 -20px 34px -16px var(--color-tcl14-shade), inset 0 24px 34px -10px var(--color-tcl14-light);
--shadow-tcl14-cta: 0 16px 28px -12px var(--color-tcl14-shade), inset 0 -12px 20px -9px var(--color-tcl14-shade), inset 0 14px 20px -7px var(--color-tcl14-light);
--shadow-tcl14-ghost: 0 12px 20px -12px var(--color-tcl14-shade), inset 0 -9px 15px -9px var(--color-tcl14-shade), inset 0 11px 15px -7px var(--color-tcl14-light);
--shadow-tcl14-press: 0 0 0 0 transparent, inset 0 12px 18px -8px var(--color-tcl14-shade), inset 0 -6px 12px -9px var(--color-tcl14-light);
--shadow-tcl14-row: inset 0 -6px 11px -8px var(--color-tcl14-shade), inset 0 7px 11px -6px var(--color-tcl14-light);
--shadow-tcl14-fact: inset 0 -4px 8px -7px var(--color-tcl14-shade), inset 0 5px 8px -5px white;
--shadow-tcl14-tick: inset 0 5px 7px -4px oklch(1 0 0 / 0.6), 0 4px 7px -4px var(--color-tcl14-shade);
}
/* 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. */
.tcl-14 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tcl14-bg: #ebe3fc;
--color-tcl14-bg: oklch(0.93 0.035 300);
--color-tcl14-glow: #fcefff;
--color-tcl14-glow: oklch(0.97 0.035 310);
--color-tcl14-page: #f2edfd;
--color-tcl14-page: oklch(0.955 0.022 300);
--color-tcl14-clay: #e3d7fb;
--color-tcl14-clay: oklch(0.9 0.05 300);
--color-tcl14-soft: #eee7ff;
--color-tcl14-soft: oklch(0.94 0.034 300);
--color-tcl14-accent: #c9a5ff;
--color-tcl14-accent: oklch(0.79 0.14 300);
--color-tcl14-accentink: #26133f;
--color-tcl14-accentink: oklch(0.24 0.08 300);
--color-tcl14-ok: #00884b;
--color-tcl14-ok: oklch(0.55 0.14 155);
--color-tcl14-scrim: #3d30526b;
--color-tcl14-scrim: oklch(0.34 0.06 300 / 0.42);
--color-tcl14-shade: #6c55948c;
--color-tcl14-shade: oklch(0.5 0.1 300 / 0.55);
--color-tcl14-light: #fffdfff2;
--color-tcl14-light: oklch(1 0.012 300 / 0.95);
--color-tcl14-ink: #291c3c;
--color-tcl14-ink: oklch(0.26 0.06 300);
--color-tcl14-mut: #594f6d;
--color-tcl14-mut: oklch(0.45 0.05 300);
--font-tcl14-display: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tcl14-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tcl14-mono: 'JetBrains Mono', ui-monospace, monospace;
--shadow-tcl14-page: 0 26px 48px -20px var(--color-tcl14-shade), inset 0 -16px 28px -16px var(--color-tcl14-shade), inset 0 18px 28px -12px var(--color-tcl14-light);
--shadow-tcl14-modal: 0 60px 110px -30px oklch(0.32 0.08 300 / 0.65), 0 24px 44px -16px var(--color-tcl14-shade), inset 0 -20px 34px -16px var(--color-tcl14-shade), inset 0 24px 34px -10px var(--color-tcl14-light);
--shadow-tcl14-cta: 0 16px 28px -12px var(--color-tcl14-shade), inset 0 -12px 20px -9px var(--color-tcl14-shade), inset 0 14px 20px -7px var(--color-tcl14-light);
--shadow-tcl14-ghost: 0 12px 20px -12px var(--color-tcl14-shade), inset 0 -9px 15px -9px var(--color-tcl14-shade), inset 0 11px 15px -7px var(--color-tcl14-light);
--shadow-tcl14-press: 0 0 0 0 transparent, inset 0 12px 18px -8px var(--color-tcl14-shade), inset 0 -6px 12px -9px var(--color-tcl14-light);
--shadow-tcl14-row: inset 0 -6px 11px -8px var(--color-tcl14-shade), inset 0 7px 11px -6px var(--color-tcl14-light);
--shadow-tcl14-fact: inset 0 -4px 8px -7px var(--color-tcl14-shade), inset 0 5px 8px -5px white;
--shadow-tcl14-tick: inset 0 5px 7px -4px oklch(1 0 0 / 0.6), 0 4px 7px -4px var(--color-tcl14-shade);
}
/* 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. */
.tcl-14 {
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=Bricolage+Grotesque:opsz,wght@12..96,500..800&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600;700&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=Bricolage+Grotesque:opsz,wght@12..96,500..800&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Seven rules —
:popover-open, two@starting-styleblocks and two::backdropstates — becameopen:,starting:open:andbackdrop:utilities on the one element. transition: display .32s allow-discrete, overlay .32s allow-discretebecametransition-[…,display,overlay] transition-discrete.- UI upgrade from the CSS original: a 44px labelled close button balances the grip — light dismiss and Escape are invisible affordances; now there's a visible one.
- UI upgrade: checklist dots became drawn checkmarks on a 4.5:1 green, so "passed" no longer relies on colour alone.
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 Dialog with Popover API (Clay Floating Depth)
Source: https://codefronts.com/design-styles/tailwind-css-claymorphism/tailwind-modal-dialog-popover-api-clay/
A tier-4 clay dialog on the native popover API — no focus-trap library, no script. The browser owns the top layer, light dismiss, Escape and focus return; Tailwind owns the rest: open:grid, starting:open:scale-94 for the entry, transition-discrete for the exit, and backdrop:backdrop-blur-[7px] for the scrim. New: a labelled close button and drawn check glyphs in the checklist.
## HTML
```html
<section class="tcl-14 w-full min-h-svh grid place-items-center bg-tcl14-bg bg-[radial-gradient(85%_60%_at_50%_0%,var(--color-tcl14-glow),transparent_68%)] px-5 py-14 font-tcl14-sans text-tcl14-ink" aria-label="Clay modal dialog with floating depth demo">
<div class="grid w-full justify-items-center gap-5">
<div class="grid w-full max-w-[640px] justify-items-center gap-3.5 rounded-[44px] bg-tcl14-page p-[clamp(26px,4vw,46px)] text-center shadow-tcl14-page">
<h2 class="font-tcl14-display text-[clamp(26px,3.8vw,36px)] font-extrabold leading-[1.08] tracking-[-0.03em] text-balance">Native popover, clay depth</h2>
<p class="max-w-[48ch] text-[15px] leading-relaxed text-tcl14-mut text-pretty">The top layer, light dismiss, Escape and focus are the browser's job. Tier-4 shadows and a blurred backdrop are ours.</p>
<button type="button" popovertarget="tcl-14-dialog" class="mt-1.5 min-h-[58px] cursor-pointer rounded-[26px] bg-tcl14-accent px-8.5 text-base font-bold text-tcl14-accentink shadow-tcl14-cta transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-1 active:translate-y-0.75 active:scale-y-93 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-tcl14-ink">Publish collection</button>
<ul class="mt-1.5 flex flex-wrap justify-center gap-2" aria-label="Techniques">
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">popover="auto"</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">starting:open:</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">transition-discrete</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">backdrop:backdrop-blur</li>
</ul>
</div>
<div id="tcl-14-dialog" popover="auto" aria-labelledby="tcl-14-title" class="fixed inset-0 m-auto max-h-[86svh] w-[min(92vw,460px)] translate-y-3 scale-94 gap-3.5 overflow-auto rounded-[40px] border-0 bg-tcl14-clay p-[clamp(24px,3.6vw,34px)] text-tcl14-ink opacity-0 shadow-tcl14-modal transition-[opacity,scale,translate,display,overlay] transition-discrete duration-300 ease-[cubic-bezier(.2,.9,.3,1.15)] open:grid open:translate-y-0 open:scale-100 open:opacity-100 starting:open:translate-y-3 starting:open:scale-94 starting:open:opacity-0 backdrop:bg-tcl14-scrim backdrop:opacity-0 backdrop:backdrop-blur-[7px] backdrop:transition-[opacity,display,overlay] backdrop:transition-discrete backdrop:duration-300 open:backdrop:opacity-100 starting:open:backdrop:opacity-0 motion-reduce:transition-none">
<div class="flex items-center justify-between">
<span aria-hidden="true" class="w-11"></span>
<span aria-hidden="true" class="h-1.5 w-13.5 rounded-full bg-tcl14-shade/40 shadow-[inset_0_2px_3px_-1px_var(--color-tcl14-shade)]"></span>
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" aria-label="Close" class="grid size-11 cursor-pointer place-items-center rounded-full bg-tcl14-soft text-tcl14-ink shadow-tcl14-ghost transition-[translate] hover:-translate-y-0.5 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tcl14-ink"><svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8"/></svg></button>
</div>
<h3 id="tcl-14-title" class="font-tcl14-display text-[clamp(21px,3vw,25px)] font-extrabold tracking-[-0.025em] text-balance">Publish “20 Tailwind Claymorphism”?</h3>
<p class="text-[14.5px] leading-relaxed text-tcl14-ink/85 text-pretty">All 20 demos become public and the collection page goes live at once. You can unpublish any single demo later.</p>
<ul class="mt-0.5 mb-1 grid gap-2">
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Snippets validated</li>
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Reduced-motion pass</li>
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Contrast pass</li>
</ul>
<div class="mt-1 flex flex-wrap gap-2.5">
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" class="min-h-13 min-w-[130px] flex-1 cursor-pointer rounded-3xl bg-tcl14-soft px-5.5 text-[14.5px] font-bold text-tcl14-ink shadow-tcl14-ghost transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-0.75 active:translate-y-0.75 active:scale-y-94 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcl14-ink">Not yet</button>
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" class="min-h-13 min-w-[130px] flex-1 cursor-pointer rounded-3xl bg-tcl14-accent px-5.5 text-[14.5px] font-bold text-tcl14-accentink shadow-tcl14-cta transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-0.75 active:translate-y-0.75 active:scale-y-94 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcl14-ink">Publish now</button>
</div>
</div>
<p aria-hidden="true" class="rounded-full bg-white/55 px-4 py-2 text-center font-tcl14-mono text-[11.5px] text-tcl14-mut">tier-4 elevation · open: + starting:open: · transition-discrete · native top layer</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcl14-bg: #ebe3fc;
--color-tcl14-bg: oklch(0.93 0.035 300);
--color-tcl14-glow: #fcefff;
--color-tcl14-glow: oklch(0.97 0.035 310);
--color-tcl14-page: #f2edfd;
--color-tcl14-page: oklch(0.955 0.022 300);
--color-tcl14-clay: #e3d7fb;
--color-tcl14-clay: oklch(0.9 0.05 300);
--color-tcl14-soft: #eee7ff;
--color-tcl14-soft: oklch(0.94 0.034 300);
--color-tcl14-accent: #c9a5ff;
--color-tcl14-accent: oklch(0.79 0.14 300);
--color-tcl14-accentink: #26133f;
--color-tcl14-accentink: oklch(0.24 0.08 300);
--color-tcl14-ok: #00884b;
--color-tcl14-ok: oklch(0.55 0.14 155);
--color-tcl14-scrim: #3d30526b;
--color-tcl14-scrim: oklch(0.34 0.06 300 / 0.42);
--color-tcl14-shade: #6c55948c;
--color-tcl14-shade: oklch(0.5 0.1 300 / 0.55);
--color-tcl14-light: #fffdfff2;
--color-tcl14-light: oklch(1 0.012 300 / 0.95);
--color-tcl14-ink: #291c3c;
--color-tcl14-ink: oklch(0.26 0.06 300);
--color-tcl14-mut: #594f6d;
--color-tcl14-mut: oklch(0.45 0.05 300);
--font-tcl14-display: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tcl14-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tcl14-mono: 'JetBrains Mono', ui-monospace, monospace;
--shadow-tcl14-page: 0 26px 48px -20px var(--color-tcl14-shade), inset 0 -16px 28px -16px var(--color-tcl14-shade), inset 0 18px 28px -12px var(--color-tcl14-light);
--shadow-tcl14-modal: 0 60px 110px -30px oklch(0.32 0.08 300 / 0.65), 0 24px 44px -16px var(--color-tcl14-shade), inset 0 -20px 34px -16px var(--color-tcl14-shade), inset 0 24px 34px -10px var(--color-tcl14-light);
--shadow-tcl14-cta: 0 16px 28px -12px var(--color-tcl14-shade), inset 0 -12px 20px -9px var(--color-tcl14-shade), inset 0 14px 20px -7px var(--color-tcl14-light);
--shadow-tcl14-ghost: 0 12px 20px -12px var(--color-tcl14-shade), inset 0 -9px 15px -9px var(--color-tcl14-shade), inset 0 11px 15px -7px var(--color-tcl14-light);
--shadow-tcl14-press: 0 0 0 0 transparent, inset 0 12px 18px -8px var(--color-tcl14-shade), inset 0 -6px 12px -9px var(--color-tcl14-light);
--shadow-tcl14-row: inset 0 -6px 11px -8px var(--color-tcl14-shade), inset 0 7px 11px -6px var(--color-tcl14-light);
--shadow-tcl14-fact: inset 0 -4px 8px -7px var(--color-tcl14-shade), inset 0 5px 8px -5px white;
--shadow-tcl14-tick: inset 0 5px 7px -4px oklch(1 0 0 / 0.6), 0 4px 7px -4px var(--color-tcl14-shade);
}
/* 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. */
.tcl-14 {
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 Dialog with Popover API (Clay Floating Depth)
Source: https://codefronts.com/design-styles/tailwind-css-claymorphism/tailwind-modal-dialog-popover-api-clay/
A tier-4 clay dialog on the native popover API — no focus-trap library, no script. The browser owns the top layer, light dismiss, Escape and focus return; Tailwind owns the rest: open:grid, starting:open:scale-94 for the entry, transition-discrete for the exit, and backdrop:backdrop-blur-[7px] for the scrim. New: a labelled close button and drawn check glyphs in the checklist.
## HTML
```html
<section class="tcl-14 w-full min-h-svh grid place-items-center bg-tcl14-bg bg-[radial-gradient(85%_60%_at_50%_0%,var(--color-tcl14-glow),transparent_68%)] px-5 py-14 font-tcl14-sans text-tcl14-ink" aria-label="Clay modal dialog with floating depth demo">
<div class="grid w-full justify-items-center gap-5">
<div class="grid w-full max-w-[640px] justify-items-center gap-3.5 rounded-[44px] bg-tcl14-page p-[clamp(26px,4vw,46px)] text-center shadow-tcl14-page">
<h2 class="font-tcl14-display text-[clamp(26px,3.8vw,36px)] font-extrabold leading-[1.08] tracking-[-0.03em] text-balance">Native popover, clay depth</h2>
<p class="max-w-[48ch] text-[15px] leading-relaxed text-tcl14-mut text-pretty">The top layer, light dismiss, Escape and focus are the browser's job. Tier-4 shadows and a blurred backdrop are ours.</p>
<button type="button" popovertarget="tcl-14-dialog" class="mt-1.5 min-h-[58px] cursor-pointer rounded-[26px] bg-tcl14-accent px-8.5 text-base font-bold text-tcl14-accentink shadow-tcl14-cta transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-1 active:translate-y-0.75 active:scale-y-93 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-tcl14-ink">Publish collection</button>
<ul class="mt-1.5 flex flex-wrap justify-center gap-2" aria-label="Techniques">
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">popover="auto"</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">starting:open:</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">transition-discrete</li>
<li class="rounded-full bg-white/65 px-3 py-1.75 font-tcl14-mono text-[11px] text-tcl14-mut shadow-tcl14-fact">backdrop:backdrop-blur</li>
</ul>
</div>
<div id="tcl-14-dialog" popover="auto" aria-labelledby="tcl-14-title" class="fixed inset-0 m-auto max-h-[86svh] w-[min(92vw,460px)] translate-y-3 scale-94 gap-3.5 overflow-auto rounded-[40px] border-0 bg-tcl14-clay p-[clamp(24px,3.6vw,34px)] text-tcl14-ink opacity-0 shadow-tcl14-modal transition-[opacity,scale,translate,display,overlay] transition-discrete duration-300 ease-[cubic-bezier(.2,.9,.3,1.15)] open:grid open:translate-y-0 open:scale-100 open:opacity-100 starting:open:translate-y-3 starting:open:scale-94 starting:open:opacity-0 backdrop:bg-tcl14-scrim backdrop:opacity-0 backdrop:backdrop-blur-[7px] backdrop:transition-[opacity,display,overlay] backdrop:transition-discrete backdrop:duration-300 open:backdrop:opacity-100 starting:open:backdrop:opacity-0 motion-reduce:transition-none">
<div class="flex items-center justify-between">
<span aria-hidden="true" class="w-11"></span>
<span aria-hidden="true" class="h-1.5 w-13.5 rounded-full bg-tcl14-shade/40 shadow-[inset_0_2px_3px_-1px_var(--color-tcl14-shade)]"></span>
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" aria-label="Close" class="grid size-11 cursor-pointer place-items-center rounded-full bg-tcl14-soft text-tcl14-ink shadow-tcl14-ghost transition-[translate] hover:-translate-y-0.5 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tcl14-ink"><svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8"/></svg></button>
</div>
<h3 id="tcl-14-title" class="font-tcl14-display text-[clamp(21px,3vw,25px)] font-extrabold tracking-[-0.025em] text-balance">Publish “20 Tailwind Claymorphism”?</h3>
<p class="text-[14.5px] leading-relaxed text-tcl14-ink/85 text-pretty">All 20 demos become public and the collection page goes live at once. You can unpublish any single demo later.</p>
<ul class="mt-0.5 mb-1 grid gap-2">
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Snippets validated</li>
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Reduced-motion pass</li>
<li class="flex items-center gap-2.75 rounded-[20px] bg-tcl14-soft px-3.75 py-2.75 text-[13.5px] font-semibold shadow-tcl14-row"><span aria-hidden="true" class="grid size-5.5 flex-none place-items-center rounded-full bg-tcl14-ok text-white shadow-tcl14-tick"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg></span>Contrast pass</li>
</ul>
<div class="mt-1 flex flex-wrap gap-2.5">
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" class="min-h-13 min-w-[130px] flex-1 cursor-pointer rounded-3xl bg-tcl14-soft px-5.5 text-[14.5px] font-bold text-tcl14-ink shadow-tcl14-ghost transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-0.75 active:translate-y-0.75 active:scale-y-94 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcl14-ink">Not yet</button>
<button type="button" popovertarget="tcl-14-dialog" popovertargetaction="hide" class="min-h-13 min-w-[130px] flex-1 cursor-pointer rounded-3xl bg-tcl14-accent px-5.5 text-[14.5px] font-bold text-tcl14-accentink shadow-tcl14-cta transition-[translate,scale,box-shadow] duration-200 ease-[cubic-bezier(.2,.8,.3,1.4)] hover:-translate-y-0.75 active:translate-y-0.75 active:scale-y-94 active:shadow-tcl14-press focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tcl14-ink">Publish now</button>
</div>
</div>
<p aria-hidden="true" class="rounded-full bg-white/55 px-4 py-2 text-center font-tcl14-mono text-[11.5px] text-tcl14-mut">tier-4 elevation · open: + starting:open: · transition-discrete · native top layer</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcl14-bg: #ebe3fc;
--color-tcl14-bg: oklch(0.93 0.035 300);
--color-tcl14-glow: #fcefff;
--color-tcl14-glow: oklch(0.97 0.035 310);
--color-tcl14-page: #f2edfd;
--color-tcl14-page: oklch(0.955 0.022 300);
--color-tcl14-clay: #e3d7fb;
--color-tcl14-clay: oklch(0.9 0.05 300);
--color-tcl14-soft: #eee7ff;
--color-tcl14-soft: oklch(0.94 0.034 300);
--color-tcl14-accent: #c9a5ff;
--color-tcl14-accent: oklch(0.79 0.14 300);
--color-tcl14-accentink: #26133f;
--color-tcl14-accentink: oklch(0.24 0.08 300);
--color-tcl14-ok: #00884b;
--color-tcl14-ok: oklch(0.55 0.14 155);
--color-tcl14-scrim: #3d30526b;
--color-tcl14-scrim: oklch(0.34 0.06 300 / 0.42);
--color-tcl14-shade: #6c55948c;
--color-tcl14-shade: oklch(0.5 0.1 300 / 0.55);
--color-tcl14-light: #fffdfff2;
--color-tcl14-light: oklch(1 0.012 300 / 0.95);
--color-tcl14-ink: #291c3c;
--color-tcl14-ink: oklch(0.26 0.06 300);
--color-tcl14-mut: #594f6d;
--color-tcl14-mut: oklch(0.45 0.05 300);
--font-tcl14-display: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tcl14-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-tcl14-mono: 'JetBrains Mono', ui-monospace, monospace;
--shadow-tcl14-page: 0 26px 48px -20px var(--color-tcl14-shade), inset 0 -16px 28px -16px var(--color-tcl14-shade), inset 0 18px 28px -12px var(--color-tcl14-light);
--shadow-tcl14-modal: 0 60px 110px -30px oklch(0.32 0.08 300 / 0.65), 0 24px 44px -16px var(--color-tcl14-shade), inset 0 -20px 34px -16px var(--color-tcl14-shade), inset 0 24px 34px -10px var(--color-tcl14-light);
--shadow-tcl14-cta: 0 16px 28px -12px var(--color-tcl14-shade), inset 0 -12px 20px -9px var(--color-tcl14-shade), inset 0 14px 20px -7px var(--color-tcl14-light);
--shadow-tcl14-ghost: 0 12px 20px -12px var(--color-tcl14-shade), inset 0 -9px 15px -9px var(--color-tcl14-shade), inset 0 11px 15px -7px var(--color-tcl14-light);
--shadow-tcl14-press: 0 0 0 0 transparent, inset 0 12px 18px -8px var(--color-tcl14-shade), inset 0 -6px 12px -9px var(--color-tcl14-light);
--shadow-tcl14-row: inset 0 -6px 11px -8px var(--color-tcl14-shade), inset 0 7px 11px -6px var(--color-tcl14-light);
--shadow-tcl14-fact: inset 0 -4px 8px -7px var(--color-tcl14-shade), inset 0 5px 8px -5px white;
--shadow-tcl14-tick: inset 0 5px 7px -4px oklch(1 0 0 / 0.6), 0 4px 7px -4px var(--color-tcl14-shade);
}
/* 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. */
.tcl-14 {
width: 100%;
min-height: 100svh;
}
```How this works
Never set display in the base state. The UA hides a closed popover with display:none; a plain grid class would override that and show it forever. Put layout behind the variant:
<div popover class="opacity-0 scale-94 translate-y-3
open:grid open:opacity-100 open:scale-100 open:translate-y-0
starting:open:opacity-0 starting:open:scale-94
transition-[opacity,scale,translate,display,overlay] transition-discrete">Why overlay too. On close the element leaves the top layer; transitioning overlay discretely keeps it on top until the fade finishes, so the exit is visible.
Buttons do the wiring. popovertarget opens, popovertargetaction="hide" closes — zero JavaScript.
Make it yours
- Sheet on mobile: add
max-sm:mt-auto max-sm:mb-0 max-sm:rounded-b-nonefor a bottom sheet. - Hard modal: switch to
popover="manual"to disable light dismiss (keep the close button). - Tone: edit
--color-tcl14-accent; the CTA and trigger follow.
Gotchas — read before shipping
popoveris not<dialog>.showModal(): the page behind stays interactive to assistive tech. For destructive confirmations that must block, use a modal<dialog>.starting:must be combined withopen:; without it the entry state applies to the closed popover too.- Browsers without
transition-behaviorstill open and close instantly — a correct fallback.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17+ | 125+ | 114+ |
Popover is Chrome 114 / Safari 17 / Firefox 125; animated exits need transition-behavior (Chrome 117 / Safari 17.4 / Firefox 129).