23 / 51
All 51 in 51 Tailwind CSS Buttons
- 01Tailwind Submit Button (Form Primary)
- 02Tailwind Primary and Secondary Button Pair
- 03Tailwind Ghost / Outline Button
- 04Tailwind Icon-Only Button with Accessible Tooltip
- 05Tailwind Gradient CTA Button
- 06Tailwind Loading Spinner Button (State Transition)
- 07Tailwind Disabled Button State (Full State Reference)
- 08Tailwind Button Group Component (Segmented Radio-Like)
- 09Tailwind Add to Cart Button
- 10Tailwind Download Progress Button
- 11Tailwind Like Heart Button
- 12Tailwind Confirm Delete Button
- 13Tailwind Play Pause Button
- 14Tailwind Subscribe Confetti Button
- 15Tailwind Magnetic Mercury Ripple Button
- 16Tailwind Brutalist Glitch Button
- 17Tailwind Neon Plasma Burst Button
- 18Tailwind Clay Press Button
- 19Tailwind Editorial Ink Spread Button
- 20Tailwind Particle Shard Burst Button
- 21Tailwind Brushed Brass Plate Button
- 22Tailwind Washi Paper Crane Button
- 23Tailwind Frosted Ice Cube Button
- 24Tailwind Vintage Typewriter Key Button
- 25Tailwind Lacquered Walnut Wood Button
- 26Tailwind Pharma Gel Capsule Button
- 27Tailwind Aged Copper Coin Button
- 28Tailwind Origami Fortune Cookie Button
- 29Tailwind Holographic Foil Sticker Button
- 30Tailwind Brutalist Concrete Slab Button
- 31Tailwind Mercury Bead Morph Button
- 32Tailwind Soft Pill Modern SaaS Button
- 33Tailwind Masking Tape Label Button
- 34Tailwind Obsidian Glass Shard Button
- 35Tailwind Wine Velvet Ribbon Button
- 36Tailwind LED Segment Display Button
- 37Tailwind Cassette Mixtape Label Button
- 38Tailwind Chalkboard Menu Button
- 39Tailwind Vinyl Record Sleeve Ripple Button
- 40Tailwind Polaroid Snapshot Button
- 41Tailwind Airline Boarding Pass Button
- 42Tailwind Aged Brass Subway Token Button
- 43Tailwind Vintage Rx Pharmacy Label Button
- 44Tailwind Bakelite Radio Dial Toggle Button
- 45Tailwind Regal Postage Stamp Button
- 46Tailwind Victorian Cigar Band Foil Button
- 47Tailwind Vintage Calculator Key Button
- 48Tailwind Toolbox Latch Spotlight Button
- 49Tailwind Receipt Paper Total Count-Up Button
- 50Tailwind IBM Punch Card Magnetic Follow Button
- 51Tailwind Brass Periscope Lens Button
Tailwind Frosted Ice Cube Button
Real frosted glass over a photograph: backdrop-blur and backdrop-saturate handle the refraction, a bright inner rim catches the light on two edges only, frost collects in the corners, and pressing sends a hairline crack across the face.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<div class="tb-23 w-full min-h-svh bg-tb23-fallback font-tb23-sans antialiased">
<div class="relative min-h-svh grid place-items-center overflow-hidden p-[clamp(1.5rem,6vw,4rem)]">
<img src="https://images.unsplash.com/photo-1518495973542-4542c06a5843?w=1600&q=70&auto=format&fit=crop" alt="" width="1600" height="1000" loading="lazy" decoding="async" class="absolute inset-0 size-full object-cover bg-tb23-fallback saturate-105 brightness-90">
<button type="button" class="group relative overflow-hidden z-10 cursor-pointer min-h-15 px-8 border-0 rounded-[1.1rem] text-base font-semibold tracking-[-0.005em] text-tb23-ink bg-[linear-gradient(150deg,rgba(255,255,255,0.30),rgba(255,255,255,0.08))] [text-shadow:0_1px_12px_rgba(4,20,32,0.65)] backdrop-blur-[16px] backdrop-saturate-150 backdrop-brightness-105 shadow-[inset_1px_1px_0_rgba(255,255,255,0.7),inset_-1px_-1px_0_rgba(255,255,255,0.18),inset_0_0_24px_rgba(255,255,255,0.14),0_20px_44px_-20px_rgba(4,16,26,0.75)] transition-[translate,box-shadow,scale] duration-300 ease-tb23-out hover:-translate-y-0.5 hover:shadow-[inset_1px_1px_0_rgba(255,255,255,0.85),inset_-1px_-1px_0_rgba(255,255,255,0.22),inset_0_0_30px_rgba(255,255,255,0.2),0_26px_50px_-20px_rgba(4,16,26,0.8)] active:scale-[0.985] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white/90 supports-[not_(backdrop-filter:blur(4px))]:bg-tb23-solid supports-[not_(backdrop-filter:blur(4px))]:text-tb23-ink-solid supports-[not_(backdrop-filter:blur(4px))]:[text-shadow:none] motion-reduce:transition-none">
<span aria-hidden="true" class="tb-23__frost absolute inset-0 z-10 pointer-events-none opacity-85 transition-opacity duration-[350ms] group-hover:opacity-100 motion-reduce:transition-none"></span>
<span aria-hidden="true" class="absolute inset-0 z-20 pointer-events-none opacity-0 bg-white/95 [clip-path:polygon(0_52%,18%_44%,26%_58%,44%_40%,58%_56%,72%_38%,86%_52%,100%_44%,100%_46%,86%_54%,72%_41%,58%_59%,44%_43%,26%_61%,18%_47%,0_54%)] group-active:animate-tb23-crack motion-reduce:hidden"></span>
<span class="relative z-30 grid grid-flow-col items-center gap-2">
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" class="size-[1.15rem]"><path d="M12 3v18M4 7.5l16 9M20 7.5l-16 9"/></svg>
<span>Chill mode</span>
</span>
</button>
</div>
</div><div class="tb-23 w-full min-h-svh bg-tb23-fallback font-tb23-sans antialiased">
<div class="relative min-h-svh grid place-items-center overflow-hidden p-[clamp(1.5rem,6vw,4rem)]">
<img src="https://images.unsplash.com/photo-1518495973542-4542c06a5843?w=1600&q=70&auto=format&fit=crop" alt="" width="1600" height="1000" loading="lazy" decoding="async" class="absolute inset-0 size-full object-cover bg-tb23-fallback saturate-105 brightness-90">
<button type="button" class="group relative overflow-hidden z-10 cursor-pointer min-h-15 px-8 border-0 rounded-[1.1rem] text-base font-semibold tracking-[-0.005em] text-tb23-ink bg-[linear-gradient(150deg,rgba(255,255,255,0.30),rgba(255,255,255,0.08))] [text-shadow:0_1px_12px_rgba(4,20,32,0.65)] backdrop-blur-[16px] backdrop-saturate-150 backdrop-brightness-105 shadow-[inset_1px_1px_0_rgba(255,255,255,0.7),inset_-1px_-1px_0_rgba(255,255,255,0.18),inset_0_0_24px_rgba(255,255,255,0.14),0_20px_44px_-20px_rgba(4,16,26,0.75)] transition-[translate,box-shadow,scale] duration-300 ease-tb23-out hover:-translate-y-0.5 hover:shadow-[inset_1px_1px_0_rgba(255,255,255,0.85),inset_-1px_-1px_0_rgba(255,255,255,0.22),inset_0_0_30px_rgba(255,255,255,0.2),0_26px_50px_-20px_rgba(4,16,26,0.8)] active:scale-[0.985] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white/90 supports-[not_(backdrop-filter:blur(4px))]:bg-tb23-solid supports-[not_(backdrop-filter:blur(4px))]:text-tb23-ink-solid supports-[not_(backdrop-filter:blur(4px))]:[text-shadow:none] motion-reduce:transition-none">
<span aria-hidden="true" class="tb-23__frost absolute inset-0 z-10 pointer-events-none opacity-85 transition-opacity duration-[350ms] group-hover:opacity-100 motion-reduce:transition-none"></span>
<span aria-hidden="true" class="absolute inset-0 z-20 pointer-events-none opacity-0 bg-white/95 [clip-path:polygon(0_52%,18%_44%,26%_58%,44%_40%,58%_56%,72%_38%,86%_52%,100%_44%,100%_46%,86%_54%,72%_41%,58%_59%,44%_43%,26%_61%,18%_47%,0_54%)] group-active:animate-tb23-crack motion-reduce:hidden"></span>
<span class="relative z-30 grid grid-flow-col items-center gap-2">
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" class="size-[1.15rem]"><path d="M12 3v18M4 7.5l16 9M20 7.5l-16 9"/></svg>
<span>Chill mode</span>
</span>
</button>
</div>
</div>@import "tailwindcss";
@theme {
--color-tb23-fallback: #123044;
--color-tb23-fallback: oklch(0.32 0.05 235);
--color-tb23-ink: #f2fbff;
--color-tb23-ink-solid: #0b2434;
--color-tb23-ink-solid: oklch(0.25 0.04 235);
--color-tb23-solid: #d9ecf7b3;
--color-tb23-solid: oklch(0.92 0.02 225 / 0.7);
--font-tb23-sans: "Outfit", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb23-out: cubic-bezier(0.16, 1, 0.3, 1);
--animate-tb23-crack: tb-23-crack 0.5s ease-out;
}
@keyframes tb-23-crack {
0% {
opacity: 0;
scale: 0.4 1;
}
30% {
opacity: 0.9;
}
100% {
opacity: 0;
scale: 1 1;
}
}
.tb-23 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
}
/* FROST BLOOM: two large soft corner gradients + a fine speckle. Ice reads as
uneven — a uniform white overlay always looks like plastic. */
.tb-23__frost {
background: radial-gradient(4rem 3rem at 8% 4%, rgba(255,255,255,.42), transparent 70%), radial-gradient(5rem 3.5rem at 96% 100%, rgba(255,255,255,.34), transparent 72%), radial-gradient(.06rem .06rem at 22% 62%, rgba(255,255,255,.9) 99%, transparent), radial-gradient(.05rem .05rem at 71% 28%, rgba(255,255,255,.8) 99%, transparent);
background-size: 100% 100%, 100% 100%, 9px 9px, 14px 14px;
}
@media (forced-colors: active) {
.tb-23 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
backdrop-filter: none;
-webkit-backdrop-filter: none;
box-shadow: none;
text-shadow: none;
}
.tb-23 button span[aria-hidden] {
display: none;
}
}@import "tailwindcss";
@theme {
--color-tb23-fallback: #123044;
--color-tb23-fallback: oklch(0.32 0.05 235);
--color-tb23-ink: #f2fbff;
--color-tb23-ink-solid: #0b2434;
--color-tb23-ink-solid: oklch(0.25 0.04 235);
--color-tb23-solid: #d9ecf7b3;
--color-tb23-solid: oklch(0.92 0.02 225 / 0.7);
--font-tb23-sans: "Outfit", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb23-out: cubic-bezier(0.16, 1, 0.3, 1);
--animate-tb23-crack: tb-23-crack 0.5s ease-out;
}
@keyframes tb-23-crack {
0% {
opacity: 0;
scale: 0.4 1;
}
30% {
opacity: 0.9;
}
100% {
opacity: 0;
scale: 1 1;
}
}
.tb-23 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
}
/* FROST BLOOM: two large soft corner gradients + a fine speckle. Ice reads as
uneven — a uniform white overlay always looks like plastic. */
.tb-23__frost {
background: radial-gradient(4rem 3rem at 8% 4%, rgba(255,255,255,.42), transparent 70%), radial-gradient(5rem 3.5rem at 96% 100%, rgba(255,255,255,.34), transparent 72%), radial-gradient(.06rem .06rem at 22% 62%, rgba(255,255,255,.9) 99%, transparent), radial-gradient(.05rem .05rem at 71% 28%, rgba(255,255,255,.8) 99%, transparent);
background-size: 100% 100%, 100% 100%, 9px 9px, 14px 14px;
}
@media (forced-colors: active) {
.tb-23 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
backdrop-filter: none;
-webkit-backdrop-filter: none;
box-shadow: none;
text-shadow: none;
}
.tb-23 button span[aria-hidden] {
display: none;
}
}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-tb23-fallback: #123044;
--color-tb23-fallback: oklch(0.32 0.05 235);
--color-tb23-ink: #f2fbff;
--color-tb23-ink-solid: #0b2434;
--color-tb23-ink-solid: oklch(0.25 0.04 235);
--color-tb23-solid: #d9ecf7b3;
--color-tb23-solid: oklch(0.92 0.02 225 / 0.7);
--font-tb23-sans: "Outfit", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb23-out: cubic-bezier(0.16, 1, 0.3, 1);
--animate-tb23-crack: tb-23-crack 0.5s ease-out;
}
@keyframes tb-23-crack {
0% {
opacity: 0;
scale: 0.4 1;
}
30% {
opacity: 0.9;
}
100% {
opacity: 0;
scale: 1 1;
}
}
.tb-23 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
}
/* FROST BLOOM: two large soft corner gradients + a fine speckle. Ice reads as
uneven — a uniform white overlay always looks like plastic. */
.tb-23__frost {
background: radial-gradient(4rem 3rem at 8% 4%, rgba(255,255,255,.42), transparent 70%), radial-gradient(5rem 3.5rem at 96% 100%, rgba(255,255,255,.34), transparent 72%), radial-gradient(.06rem .06rem at 22% 62%, rgba(255,255,255,.9) 99%, transparent), radial-gradient(.05rem .05rem at 71% 28%, rgba(255,255,255,.8) 99%, transparent);
background-size: 100% 100%, 100% 100%, 9px 9px, 14px 14px;
}
@media (forced-colors: active) {
.tb-23 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
backdrop-filter: none;
-webkit-backdrop-filter: none;
box-shadow: none;
text-shadow: none;
}
.tb-23 button span[aria-hidden] {
display: none;
}
}@import "tailwindcss";
@theme {
--color-tb23-fallback: #123044;
--color-tb23-fallback: oklch(0.32 0.05 235);
--color-tb23-ink: #f2fbff;
--color-tb23-ink-solid: #0b2434;
--color-tb23-ink-solid: oklch(0.25 0.04 235);
--color-tb23-solid: #d9ecf7b3;
--color-tb23-solid: oklch(0.92 0.02 225 / 0.7);
--font-tb23-sans: "Outfit", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb23-out: cubic-bezier(0.16, 1, 0.3, 1);
--animate-tb23-crack: tb-23-crack 0.5s ease-out;
}
@keyframes tb-23-crack {
0% {
opacity: 0;
scale: 0.4 1;
}
30% {
opacity: 0.9;
}
100% {
opacity: 0;
scale: 1 1;
}
}
.tb-23 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
}
/* FROST BLOOM: two large soft corner gradients + a fine speckle. Ice reads as
uneven — a uniform white overlay always looks like plastic. */
.tb-23__frost {
background: radial-gradient(4rem 3rem at 8% 4%, rgba(255,255,255,.42), transparent 70%), radial-gradient(5rem 3.5rem at 96% 100%, rgba(255,255,255,.34), transparent 72%), radial-gradient(.06rem .06rem at 22% 62%, rgba(255,255,255,.9) 99%, transparent), radial-gradient(.05rem .05rem at 71% 28%, rgba(255,255,255,.8) 99%, transparent);
background-size: 100% 100%, 100% 100%, 9px 9px, 14px 14px;
}
@media (forced-colors: active) {
.tb-23 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
backdrop-filter: none;
-webkit-backdrop-filter: none;
box-shadow: none;
text-shadow: none;
}
.tb-23 button span[aria-hidden] {
display: none;
}
}<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=Outfit: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=Outfit:wght@400;500;600;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Utilities: the entire glass — backdrop filters, the rim shadow stack, the hover brightening, the crack polygon and its animation, and the no-support fallback as a
supports-[...]variant. CSS: the frost bloom (four layers) andforced-colors. - v4's backdrop-filter family is the single biggest free win in the collection:
backdrop-blur-[16px] backdrop-saturate-150 backdrop-brightness-105replaces two prefixed declarations and emits the-webkit-form for you. supports-[not_(backdrop-filter:blur(4px))]:is more valuable than it looks. In the CSS original the fallback lived in a separate@supports notblock that a copy-paste would leave behind; as a variant it travels with the element.- A11y fix from the CSS original: this demo is unchanged in palette but the
focus-visiblering moved fromrgba(var(--rim),.9)tooutline-white/90with a 4px offset — the original drew it atoutline-offset:4pxtoo, but over a photograph a 90%-white ring can vanish against a bright sky. The darkdrop-shadowalready on the button gives it a ground; the note is here because this is the one indicator in the collection whose contrast depends on the user's own image.
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 Frosted Ice Cube Button
Source: https://codefronts.com/components/tailwind-css-buttons/tailwind-frosted-ice-cube-button/
Real frosted glass over a photograph: backdrop-blur and backdrop-saturate handle the refraction, a bright inner rim catches the light on two edges only, frost collects in the corners, and pressing sends a hairline crack across the face.
## HTML
```html
<div class="tb-23 w-full min-h-svh bg-tb23-fallback font-tb23-sans antialiased">
<div class="relative min-h-svh grid place-items-center overflow-hidden p-[clamp(1.5rem,6vw,4rem)]">
<img src="https://images.unsplash.com/photo-1518495973542-4542c06a5843?w=1600&q=70&auto=format&fit=crop" alt="" width="1600" height="1000" loading="lazy" decoding="async" class="absolute inset-0 size-full object-cover bg-tb23-fallback saturate-105 brightness-90">
<button type="button" class="group relative overflow-hidden z-10 cursor-pointer min-h-15 px-8 border-0 rounded-[1.1rem] text-base font-semibold tracking-[-0.005em] text-tb23-ink bg-[linear-gradient(150deg,rgba(255,255,255,0.30),rgba(255,255,255,0.08))] [text-shadow:0_1px_12px_rgba(4,20,32,0.65)] backdrop-blur-[16px] backdrop-saturate-150 backdrop-brightness-105 shadow-[inset_1px_1px_0_rgba(255,255,255,0.7),inset_-1px_-1px_0_rgba(255,255,255,0.18),inset_0_0_24px_rgba(255,255,255,0.14),0_20px_44px_-20px_rgba(4,16,26,0.75)] transition-[translate,box-shadow,scale] duration-300 ease-tb23-out hover:-translate-y-0.5 hover:shadow-[inset_1px_1px_0_rgba(255,255,255,0.85),inset_-1px_-1px_0_rgba(255,255,255,0.22),inset_0_0_30px_rgba(255,255,255,0.2),0_26px_50px_-20px_rgba(4,16,26,0.8)] active:scale-[0.985] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white/90 supports-[not_(backdrop-filter:blur(4px))]:bg-tb23-solid supports-[not_(backdrop-filter:blur(4px))]:text-tb23-ink-solid supports-[not_(backdrop-filter:blur(4px))]:[text-shadow:none] motion-reduce:transition-none">
<span aria-hidden="true" class="tb-23__frost absolute inset-0 z-10 pointer-events-none opacity-85 transition-opacity duration-[350ms] group-hover:opacity-100 motion-reduce:transition-none"></span>
<span aria-hidden="true" class="absolute inset-0 z-20 pointer-events-none opacity-0 bg-white/95 [clip-path:polygon(0_52%,18%_44%,26%_58%,44%_40%,58%_56%,72%_38%,86%_52%,100%_44%,100%_46%,86%_54%,72%_41%,58%_59%,44%_43%,26%_61%,18%_47%,0_54%)] group-active:animate-tb23-crack motion-reduce:hidden"></span>
<span class="relative z-30 grid grid-flow-col items-center gap-2">
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" class="size-[1.15rem]"><path d="M12 3v18M4 7.5l16 9M20 7.5l-16 9"/></svg>
<span>Chill mode</span>
</span>
</button>
</div>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tb23-fallback: #123044;
--color-tb23-fallback: oklch(0.32 0.05 235);
--color-tb23-ink: #f2fbff;
--color-tb23-ink-solid: #0b2434;
--color-tb23-ink-solid: oklch(0.25 0.04 235);
--color-tb23-solid: #d9ecf7b3;
--color-tb23-solid: oklch(0.92 0.02 225 / 0.7);
--font-tb23-sans: "Outfit", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb23-out: cubic-bezier(0.16, 1, 0.3, 1);
--animate-tb23-crack: tb-23-crack 0.5s ease-out;
}
@keyframes tb-23-crack {
0% {
opacity: 0;
scale: 0.4 1;
}
30% {
opacity: 0.9;
}
100% {
opacity: 0;
scale: 1 1;
}
}
.tb-23 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
}
/* FROST BLOOM: two large soft corner gradients + a fine speckle. Ice reads as
uneven — a uniform white overlay always looks like plastic. */
.tb-23__frost {
background: radial-gradient(4rem 3rem at 8% 4%, rgba(255,255,255,.42), transparent 70%), radial-gradient(5rem 3.5rem at 96% 100%, rgba(255,255,255,.34), transparent 72%), radial-gradient(.06rem .06rem at 22% 62%, rgba(255,255,255,.9) 99%, transparent), radial-gradient(.05rem .05rem at 71% 28%, rgba(255,255,255,.8) 99%, transparent);
background-size: 100% 100%, 100% 100%, 9px 9px, 14px 14px;
}
@media (forced-colors: active) {
.tb-23 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
backdrop-filter: none;
-webkit-backdrop-filter: none;
box-shadow: none;
text-shadow: none;
}
.tb-23 button span[aria-hidden] {
display: none;
}
}
```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 Frosted Ice Cube Button
Source: https://codefronts.com/components/tailwind-css-buttons/tailwind-frosted-ice-cube-button/
Real frosted glass over a photograph: backdrop-blur and backdrop-saturate handle the refraction, a bright inner rim catches the light on two edges only, frost collects in the corners, and pressing sends a hairline crack across the face.
## HTML
```html
<div class="tb-23 w-full min-h-svh bg-tb23-fallback font-tb23-sans antialiased">
<div class="relative min-h-svh grid place-items-center overflow-hidden p-[clamp(1.5rem,6vw,4rem)]">
<img src="https://images.unsplash.com/photo-1518495973542-4542c06a5843?w=1600&q=70&auto=format&fit=crop" alt="" width="1600" height="1000" loading="lazy" decoding="async" class="absolute inset-0 size-full object-cover bg-tb23-fallback saturate-105 brightness-90">
<button type="button" class="group relative overflow-hidden z-10 cursor-pointer min-h-15 px-8 border-0 rounded-[1.1rem] text-base font-semibold tracking-[-0.005em] text-tb23-ink bg-[linear-gradient(150deg,rgba(255,255,255,0.30),rgba(255,255,255,0.08))] [text-shadow:0_1px_12px_rgba(4,20,32,0.65)] backdrop-blur-[16px] backdrop-saturate-150 backdrop-brightness-105 shadow-[inset_1px_1px_0_rgba(255,255,255,0.7),inset_-1px_-1px_0_rgba(255,255,255,0.18),inset_0_0_24px_rgba(255,255,255,0.14),0_20px_44px_-20px_rgba(4,16,26,0.75)] transition-[translate,box-shadow,scale] duration-300 ease-tb23-out hover:-translate-y-0.5 hover:shadow-[inset_1px_1px_0_rgba(255,255,255,0.85),inset_-1px_-1px_0_rgba(255,255,255,0.22),inset_0_0_30px_rgba(255,255,255,0.2),0_26px_50px_-20px_rgba(4,16,26,0.8)] active:scale-[0.985] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white/90 supports-[not_(backdrop-filter:blur(4px))]:bg-tb23-solid supports-[not_(backdrop-filter:blur(4px))]:text-tb23-ink-solid supports-[not_(backdrop-filter:blur(4px))]:[text-shadow:none] motion-reduce:transition-none">
<span aria-hidden="true" class="tb-23__frost absolute inset-0 z-10 pointer-events-none opacity-85 transition-opacity duration-[350ms] group-hover:opacity-100 motion-reduce:transition-none"></span>
<span aria-hidden="true" class="absolute inset-0 z-20 pointer-events-none opacity-0 bg-white/95 [clip-path:polygon(0_52%,18%_44%,26%_58%,44%_40%,58%_56%,72%_38%,86%_52%,100%_44%,100%_46%,86%_54%,72%_41%,58%_59%,44%_43%,26%_61%,18%_47%,0_54%)] group-active:animate-tb23-crack motion-reduce:hidden"></span>
<span class="relative z-30 grid grid-flow-col items-center gap-2">
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" class="size-[1.15rem]"><path d="M12 3v18M4 7.5l16 9M20 7.5l-16 9"/></svg>
<span>Chill mode</span>
</span>
</button>
</div>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tb23-fallback: #123044;
--color-tb23-fallback: oklch(0.32 0.05 235);
--color-tb23-ink: #f2fbff;
--color-tb23-ink-solid: #0b2434;
--color-tb23-ink-solid: oklch(0.25 0.04 235);
--color-tb23-solid: #d9ecf7b3;
--color-tb23-solid: oklch(0.92 0.02 225 / 0.7);
--font-tb23-sans: "Outfit", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb23-out: cubic-bezier(0.16, 1, 0.3, 1);
--animate-tb23-crack: tb-23-crack 0.5s ease-out;
}
@keyframes tb-23-crack {
0% {
opacity: 0;
scale: 0.4 1;
}
30% {
opacity: 0.9;
}
100% {
opacity: 0;
scale: 1 1;
}
}
.tb-23 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
}
/* FROST BLOOM: two large soft corner gradients + a fine speckle. Ice reads as
uneven — a uniform white overlay always looks like plastic. */
.tb-23__frost {
background: radial-gradient(4rem 3rem at 8% 4%, rgba(255,255,255,.42), transparent 70%), radial-gradient(5rem 3.5rem at 96% 100%, rgba(255,255,255,.34), transparent 72%), radial-gradient(.06rem .06rem at 22% 62%, rgba(255,255,255,.9) 99%, transparent), radial-gradient(.05rem .05rem at 71% 28%, rgba(255,255,255,.8) 99%, transparent);
background-size: 100% 100%, 100% 100%, 9px 9px, 14px 14px;
}
@media (forced-colors: active) {
.tb-23 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
backdrop-filter: none;
-webkit-backdrop-filter: none;
box-shadow: none;
text-shadow: none;
}
.tb-23 button span[aria-hidden] {
display: none;
}
}
```How this works
Glass is three things, not one. A blurred backdrop, a directional rim (bright on the lit edges, dim on the far ones), and a faint internal gradient. Drop any of the three and it reads as a translucent rectangle:
class="backdrop-blur-[16px] backdrop-saturate-150
bg-[linear-gradient(150deg,rgba(255,255,255,0.30),rgba(255,255,255,0.08))]
shadow-[inset_1px_1px_0_rgba(255,255,255,0.7),inset_-1px_-1px_0_rgba(255,255,255,0.18),…]"The fallback is a variant now. supports-[not_(backdrop-filter:blur(4px))]: swaps in a solid translucent fill and a dark label — the same logic as the CSS @supports not block, but attached to the element so it cannot be forgotten when the button is copied.
Contrast is the whole risk. Text on glass is the number-one glassmorphism failure; the label keeps a text-shadow scrim and must be verified against the lightest part of the photograph, not the average.
Make it yours
- Blur radius sets the temperature: heavier reads colder, lighter reads like wet glass.
- Swap the photo freely — the glass adapts, because it blurs whatever is behind it.
- Drop
backdrop-saturate-150for a neutral frost, raise it to 180 for colour bleed. - The frost bloom's two corner gradients live in CSS; move them by editing the percentages.
- For heavier ice, add a third corner gradient rather than raising the opacity of the existing two.
Gotchas — read before shipping
backdrop-blurneeds something behind it. Over a solid page colour it does nothing at all.- Verify the label against the lightest region of your image. A 4.5:1 average is not 4.5:1.
backdrop-filtercreates a containing block and forces a compositing layer — expensive at size, and unusable behind fixed-position children.- Never animate the blur radius; it re-rasterises the backdrop every frame. Animate opacity or a separate overlay.
- Safari needs
-webkit-backdrop-filter. v4'sbackdrop-blur-*emits both, which is one fewer thing to remember than the hand-written version.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
backdrop-filter is Chrome 76 / Safari 9 (prefixed) / Firefox 103, all below Tailwind v4's floor. The supports-[not_...] variant supplies a legible solid fallback where it is missing.