18 / 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 Clay Press Button
Fat, matte, extruded clay: two inner shadows carve the highlight and the shade, an outer shadow grounds it, and pressing squashes the shape on both axes so it deforms like real material. The shadows swap direction on press — the whole demo is one shadow-[…] and its active: twin.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<div class="tb-18 w-full min-h-svh grid place-items-center font-tb18-sans p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="group cursor-pointer inline-grid grid-flow-col items-center gap-3 min-h-16 pl-5.5 pr-8 border-0 rounded-3xl text-[1.0625rem] font-extrabold tracking-[-0.01em] text-white bg-tb18-clay shadow-[inset_8px_8px_16px_var(--color-tb18-light),inset_-10px_-10px_20px_var(--color-tb18-shade),0_18px_32px_-16px_var(--color-tb18-ground)] transition-[translate,scale,box-shadow] duration-500 ease-tb18-spring [-webkit-tap-highlight-color:transparent] hover:-translate-y-[3px] active:translate-y-0.5 active:scale-x-[0.96] active:scale-y-[0.9] active:shadow-[inset_7px_7px_15px_var(--color-tb18-shade-press),inset_-7px_-7px_14px_var(--color-tb18-light-press),0_6px_12px_-10px_var(--color-tb18-ground)] focus-visible:outline-[3px] focus-visible:outline-tb18-ring focus-visible:outline-offset-[5px] disabled:cursor-not-allowed disabled:grayscale-[0.6] disabled:opacity-60 motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span aria-hidden="true" class="grid place-items-center size-8.5 rounded-full text-tb18-deep bg-tb18-chip shadow-[inset_3px_3px_6px_var(--color-tb18-light),inset_-3px_-3px_6px_var(--color-tb18-shade-chip)] transition-transform duration-500 ease-tb18-spring group-hover:rotate-90 motion-reduce:transition-none motion-reduce:group-hover:rotate-0">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" class="size-[1.05rem]"><path d="M12 5v14M5 12h14"/></svg>
</span>
<span>Make something</span>
</button>
</div><div class="tb-18 w-full min-h-svh grid place-items-center font-tb18-sans p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="group cursor-pointer inline-grid grid-flow-col items-center gap-3 min-h-16 pl-5.5 pr-8 border-0 rounded-3xl text-[1.0625rem] font-extrabold tracking-[-0.01em] text-white bg-tb18-clay shadow-[inset_8px_8px_16px_var(--color-tb18-light),inset_-10px_-10px_20px_var(--color-tb18-shade),0_18px_32px_-16px_var(--color-tb18-ground)] transition-[translate,scale,box-shadow] duration-500 ease-tb18-spring [-webkit-tap-highlight-color:transparent] hover:-translate-y-[3px] active:translate-y-0.5 active:scale-x-[0.96] active:scale-y-[0.9] active:shadow-[inset_7px_7px_15px_var(--color-tb18-shade-press),inset_-7px_-7px_14px_var(--color-tb18-light-press),0_6px_12px_-10px_var(--color-tb18-ground)] focus-visible:outline-[3px] focus-visible:outline-tb18-ring focus-visible:outline-offset-[5px] disabled:cursor-not-allowed disabled:grayscale-[0.6] disabled:opacity-60 motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span aria-hidden="true" class="grid place-items-center size-8.5 rounded-full text-tb18-deep bg-tb18-chip shadow-[inset_3px_3px_6px_var(--color-tb18-light),inset_-3px_-3px_6px_var(--color-tb18-shade-chip)] transition-transform duration-500 ease-tb18-spring group-hover:rotate-90 motion-reduce:transition-none motion-reduce:group-hover:rotate-0">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" class="size-[1.05rem]"><path d="M12 5v14M5 12h14"/></svg>
</span>
<span>Make something</span>
</button>
</div>@import "tailwindcss";
@theme {
--color-tb18-bg: #e8ecf7;
--color-tb18-bg: oklch(0.935 0.02 265);
--color-tb18-clay: #7c8cf8;
--color-tb18-clay: oklch(0.68 0.16 275);
--color-tb18-deep: #2a3480;
--color-tb18-deep: oklch(0.35 0.14 275);
--color-tb18-chip: #fbbf24;
--color-tb18-chip: oklch(0.84 0.16 82);
--color-tb18-ring: #3d4aa8;
--color-tb18-ring: oklch(0.45 0.15 275);
--color-tb18-light: #ffffff73;
--color-tb18-light-press: #ffffff52;
--color-tb18-shade: #2a34806b;
--color-tb18-shade: oklch(0.35 0.14 275 / 0.42);
--color-tb18-shade-press: #2a348061;
--color-tb18-shade-press: oklch(0.35 0.14 275 / 0.38);
--color-tb18-shade-chip: #2a34804d;
--color-tb18-shade-chip: oklch(0.35 0.14 275 / 0.3);
--color-tb18-ground: #2a3480a6;
--color-tb18-ground: oklch(0.35 0.14 275 / 0.65);
--font-tb18-sans: "Nunito", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb18-spring: cubic-bezier(0.16, 1, 0.3, 1);
}
@supports (transition-timing-function: linear(0, 1)) {
@theme {
--ease-tb18-spring: linear(0, 0.38 7%, 0.82 15%, 1.08 23%, 1.12 28%, 1.05 37%, 1 52%, 1);
}
}
.tb-18 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(30rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb18-bg);
}
@media (prefers-color-scheme: dark) {
.tb-18:not([data-theme="light"]) {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
--color-tb18-light-press: #ffffff2e;
}
}
.tb-18[data-theme="dark"] {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
}
@media (forced-colors: active) {
.tb-18 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-18 button span {
box-shadow: none;
border: 1px solid ButtonText;
}
}@import "tailwindcss";
@theme {
--color-tb18-bg: #e8ecf7;
--color-tb18-bg: oklch(0.935 0.02 265);
--color-tb18-clay: #7c8cf8;
--color-tb18-clay: oklch(0.68 0.16 275);
--color-tb18-deep: #2a3480;
--color-tb18-deep: oklch(0.35 0.14 275);
--color-tb18-chip: #fbbf24;
--color-tb18-chip: oklch(0.84 0.16 82);
--color-tb18-ring: #3d4aa8;
--color-tb18-ring: oklch(0.45 0.15 275);
--color-tb18-light: #ffffff73;
--color-tb18-light-press: #ffffff52;
--color-tb18-shade: #2a34806b;
--color-tb18-shade: oklch(0.35 0.14 275 / 0.42);
--color-tb18-shade-press: #2a348061;
--color-tb18-shade-press: oklch(0.35 0.14 275 / 0.38);
--color-tb18-shade-chip: #2a34804d;
--color-tb18-shade-chip: oklch(0.35 0.14 275 / 0.3);
--color-tb18-ground: #2a3480a6;
--color-tb18-ground: oklch(0.35 0.14 275 / 0.65);
--font-tb18-sans: "Nunito", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb18-spring: cubic-bezier(0.16, 1, 0.3, 1);
}
@supports (transition-timing-function: linear(0, 1)) {
@theme {
--ease-tb18-spring: linear(0, 0.38 7%, 0.82 15%, 1.08 23%, 1.12 28%, 1.05 37%, 1 52%, 1);
}
}
.tb-18 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(30rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb18-bg);
}
@media (prefers-color-scheme: dark) {
.tb-18:not([data-theme="light"]) {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
--color-tb18-light-press: #ffffff2e;
}
}
.tb-18[data-theme="dark"] {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
}
@media (forced-colors: active) {
.tb-18 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-18 button span {
box-shadow: none;
border: 1px solid ButtonText;
}
}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-tb18-bg: #e8ecf7;
--color-tb18-bg: oklch(0.935 0.02 265);
--color-tb18-clay: #7c8cf8;
--color-tb18-clay: oklch(0.68 0.16 275);
--color-tb18-deep: #2a3480;
--color-tb18-deep: oklch(0.35 0.14 275);
--color-tb18-chip: #fbbf24;
--color-tb18-chip: oklch(0.84 0.16 82);
--color-tb18-ring: #3d4aa8;
--color-tb18-ring: oklch(0.45 0.15 275);
--color-tb18-light: #ffffff73;
--color-tb18-light-press: #ffffff52;
--color-tb18-shade: #2a34806b;
--color-tb18-shade: oklch(0.35 0.14 275 / 0.42);
--color-tb18-shade-press: #2a348061;
--color-tb18-shade-press: oklch(0.35 0.14 275 / 0.38);
--color-tb18-shade-chip: #2a34804d;
--color-tb18-shade-chip: oklch(0.35 0.14 275 / 0.3);
--color-tb18-ground: #2a3480a6;
--color-tb18-ground: oklch(0.35 0.14 275 / 0.65);
--font-tb18-sans: "Nunito", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb18-spring: cubic-bezier(0.16, 1, 0.3, 1);
}
@supports (transition-timing-function: linear(0, 1)) {
@theme {
--ease-tb18-spring: linear(0, 0.38 7%, 0.82 15%, 1.08 23%, 1.12 28%, 1.05 37%, 1 52%, 1);
}
}
.tb-18 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(30rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb18-bg);
}
@media (prefers-color-scheme: dark) {
.tb-18:not([data-theme="light"]) {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
--color-tb18-light-press: #ffffff2e;
}
}
.tb-18[data-theme="dark"] {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
}
@media (forced-colors: active) {
.tb-18 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-18 button span {
box-shadow: none;
border: 1px solid ButtonText;
}
}@import "tailwindcss";
@theme {
--color-tb18-bg: #e8ecf7;
--color-tb18-bg: oklch(0.935 0.02 265);
--color-tb18-clay: #7c8cf8;
--color-tb18-clay: oklch(0.68 0.16 275);
--color-tb18-deep: #2a3480;
--color-tb18-deep: oklch(0.35 0.14 275);
--color-tb18-chip: #fbbf24;
--color-tb18-chip: oklch(0.84 0.16 82);
--color-tb18-ring: #3d4aa8;
--color-tb18-ring: oklch(0.45 0.15 275);
--color-tb18-light: #ffffff73;
--color-tb18-light-press: #ffffff52;
--color-tb18-shade: #2a34806b;
--color-tb18-shade: oklch(0.35 0.14 275 / 0.42);
--color-tb18-shade-press: #2a348061;
--color-tb18-shade-press: oklch(0.35 0.14 275 / 0.38);
--color-tb18-shade-chip: #2a34804d;
--color-tb18-shade-chip: oklch(0.35 0.14 275 / 0.3);
--color-tb18-ground: #2a3480a6;
--color-tb18-ground: oklch(0.35 0.14 275 / 0.65);
--font-tb18-sans: "Nunito", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb18-spring: cubic-bezier(0.16, 1, 0.3, 1);
}
@supports (transition-timing-function: linear(0, 1)) {
@theme {
--ease-tb18-spring: linear(0, 0.38 7%, 0.82 15%, 1.08 23%, 1.12 28%, 1.05 37%, 1 52%, 1);
}
}
.tb-18 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(30rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb18-bg);
}
@media (prefers-color-scheme: dark) {
.tb-18:not([data-theme="light"]) {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
--color-tb18-light-press: #ffffff2e;
}
}
.tb-18[data-theme="dark"] {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
}
@media (forced-colors: active) {
.tb-18 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-18 button span {
box-shadow: none;
border: 1px solid ButtonText;
}
}<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=Nunito:wght@600;700;800&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=Nunito:wght@600;700;800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Utilities: all of it — both shadow stacks, the squash, the lift, the chip, the spin. CSS: tokens, the
linear()spring behind@supports, the stage backdrop andforced-colors. Zero component CSS. - The
color-mix()shadow colours became six named alpha tokens —light,light-press,shade,shade-press,shade-chip,ground. Naming them turned an opaque recipe into a readable one: you can now see that the press state uses a weaker shade and a weaker light, which is why the dent looks softer than the rest state. active:scale-x-[0.96] active:scale-y-[0.9]is the one place where v4's separate scale utilities are strictly better than the CSS shorthand:scale:.96 .9is easy to misread as a single value with a typo.- A11y fix from the CSS original: the focus ring was
color-mix(in oklab, var(--deep) 60%, var(--clay))— a computed mid-tone that landed around 2.6:1 against the clay fill. The port uses an explicit--color-tb18-ringat ≈3.6:1 against both the clay and the page, which is the non-text minimum.
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 Clay Press Button
Source: https://codefronts.com/components/tailwind-css-buttons/tailwind-clay-press-button/
Fat, matte, extruded clay: two inner shadows carve the highlight and the shade, an outer shadow grounds it, and pressing squashes the shape on both axes so it deforms like real material. The shadows swap direction on press — the whole demo is one shadow-[…] and its active: twin.
## HTML
```html
<div class="tb-18 w-full min-h-svh grid place-items-center font-tb18-sans p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="group cursor-pointer inline-grid grid-flow-col items-center gap-3 min-h-16 pl-5.5 pr-8 border-0 rounded-3xl text-[1.0625rem] font-extrabold tracking-[-0.01em] text-white bg-tb18-clay shadow-[inset_8px_8px_16px_var(--color-tb18-light),inset_-10px_-10px_20px_var(--color-tb18-shade),0_18px_32px_-16px_var(--color-tb18-ground)] transition-[translate,scale,box-shadow] duration-500 ease-tb18-spring [-webkit-tap-highlight-color:transparent] hover:-translate-y-[3px] active:translate-y-0.5 active:scale-x-[0.96] active:scale-y-[0.9] active:shadow-[inset_7px_7px_15px_var(--color-tb18-shade-press),inset_-7px_-7px_14px_var(--color-tb18-light-press),0_6px_12px_-10px_var(--color-tb18-ground)] focus-visible:outline-[3px] focus-visible:outline-tb18-ring focus-visible:outline-offset-[5px] disabled:cursor-not-allowed disabled:grayscale-[0.6] disabled:opacity-60 motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span aria-hidden="true" class="grid place-items-center size-8.5 rounded-full text-tb18-deep bg-tb18-chip shadow-[inset_3px_3px_6px_var(--color-tb18-light),inset_-3px_-3px_6px_var(--color-tb18-shade-chip)] transition-transform duration-500 ease-tb18-spring group-hover:rotate-90 motion-reduce:transition-none motion-reduce:group-hover:rotate-0">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" class="size-[1.05rem]"><path d="M12 5v14M5 12h14"/></svg>
</span>
<span>Make something</span>
</button>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tb18-bg: #e8ecf7;
--color-tb18-bg: oklch(0.935 0.02 265);
--color-tb18-clay: #7c8cf8;
--color-tb18-clay: oklch(0.68 0.16 275);
--color-tb18-deep: #2a3480;
--color-tb18-deep: oklch(0.35 0.14 275);
--color-tb18-chip: #fbbf24;
--color-tb18-chip: oklch(0.84 0.16 82);
--color-tb18-ring: #3d4aa8;
--color-tb18-ring: oklch(0.45 0.15 275);
--color-tb18-light: #ffffff73;
--color-tb18-light-press: #ffffff52;
--color-tb18-shade: #2a34806b;
--color-tb18-shade: oklch(0.35 0.14 275 / 0.42);
--color-tb18-shade-press: #2a348061;
--color-tb18-shade-press: oklch(0.35 0.14 275 / 0.38);
--color-tb18-shade-chip: #2a34804d;
--color-tb18-shade-chip: oklch(0.35 0.14 275 / 0.3);
--color-tb18-ground: #2a3480a6;
--color-tb18-ground: oklch(0.35 0.14 275 / 0.65);
--font-tb18-sans: "Nunito", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb18-spring: cubic-bezier(0.16, 1, 0.3, 1);
}
@supports (transition-timing-function: linear(0, 1)) {
@theme {
--ease-tb18-spring: linear(0, 0.38 7%, 0.82 15%, 1.08 23%, 1.12 28%, 1.05 37%, 1 52%, 1);
}
}
.tb-18 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(30rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb18-bg);
}
@media (prefers-color-scheme: dark) {
.tb-18:not([data-theme="light"]) {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
--color-tb18-light-press: #ffffff2e;
}
}
.tb-18[data-theme="dark"] {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
}
@media (forced-colors: active) {
.tb-18 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-18 button span {
box-shadow: none;
border: 1px solid ButtonText;
}
}
```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 Clay Press Button
Source: https://codefronts.com/components/tailwind-css-buttons/tailwind-clay-press-button/
Fat, matte, extruded clay: two inner shadows carve the highlight and the shade, an outer shadow grounds it, and pressing squashes the shape on both axes so it deforms like real material. The shadows swap direction on press — the whole demo is one shadow-[…] and its active: twin.
## HTML
```html
<div class="tb-18 w-full min-h-svh grid place-items-center font-tb18-sans p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="group cursor-pointer inline-grid grid-flow-col items-center gap-3 min-h-16 pl-5.5 pr-8 border-0 rounded-3xl text-[1.0625rem] font-extrabold tracking-[-0.01em] text-white bg-tb18-clay shadow-[inset_8px_8px_16px_var(--color-tb18-light),inset_-10px_-10px_20px_var(--color-tb18-shade),0_18px_32px_-16px_var(--color-tb18-ground)] transition-[translate,scale,box-shadow] duration-500 ease-tb18-spring [-webkit-tap-highlight-color:transparent] hover:-translate-y-[3px] active:translate-y-0.5 active:scale-x-[0.96] active:scale-y-[0.9] active:shadow-[inset_7px_7px_15px_var(--color-tb18-shade-press),inset_-7px_-7px_14px_var(--color-tb18-light-press),0_6px_12px_-10px_var(--color-tb18-ground)] focus-visible:outline-[3px] focus-visible:outline-tb18-ring focus-visible:outline-offset-[5px] disabled:cursor-not-allowed disabled:grayscale-[0.6] disabled:opacity-60 motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span aria-hidden="true" class="grid place-items-center size-8.5 rounded-full text-tb18-deep bg-tb18-chip shadow-[inset_3px_3px_6px_var(--color-tb18-light),inset_-3px_-3px_6px_var(--color-tb18-shade-chip)] transition-transform duration-500 ease-tb18-spring group-hover:rotate-90 motion-reduce:transition-none motion-reduce:group-hover:rotate-0">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" class="size-[1.05rem]"><path d="M12 5v14M5 12h14"/></svg>
</span>
<span>Make something</span>
</button>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tb18-bg: #e8ecf7;
--color-tb18-bg: oklch(0.935 0.02 265);
--color-tb18-clay: #7c8cf8;
--color-tb18-clay: oklch(0.68 0.16 275);
--color-tb18-deep: #2a3480;
--color-tb18-deep: oklch(0.35 0.14 275);
--color-tb18-chip: #fbbf24;
--color-tb18-chip: oklch(0.84 0.16 82);
--color-tb18-ring: #3d4aa8;
--color-tb18-ring: oklch(0.45 0.15 275);
--color-tb18-light: #ffffff73;
--color-tb18-light-press: #ffffff52;
--color-tb18-shade: #2a34806b;
--color-tb18-shade: oklch(0.35 0.14 275 / 0.42);
--color-tb18-shade-press: #2a348061;
--color-tb18-shade-press: oklch(0.35 0.14 275 / 0.38);
--color-tb18-shade-chip: #2a34804d;
--color-tb18-shade-chip: oklch(0.35 0.14 275 / 0.3);
--color-tb18-ground: #2a3480a6;
--color-tb18-ground: oklch(0.35 0.14 275 / 0.65);
--font-tb18-sans: "Nunito", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb18-spring: cubic-bezier(0.16, 1, 0.3, 1);
}
@supports (transition-timing-function: linear(0, 1)) {
@theme {
--ease-tb18-spring: linear(0, 0.38 7%, 0.82 15%, 1.08 23%, 1.12 28%, 1.05 37%, 1 52%, 1);
}
}
.tb-18 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(30rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb18-bg);
}
@media (prefers-color-scheme: dark) {
.tb-18:not([data-theme="light"]) {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
--color-tb18-light-press: #ffffff2e;
}
}
.tb-18[data-theme="dark"] {
--color-tb18-bg: oklch(0.22 0.03 275);
--color-tb18-clay: oklch(0.58 0.17 275);
--color-tb18-deep: oklch(0.15 0.06 275);
--color-tb18-light: #ffffff40;
}
@media (forced-colors: active) {
.tb-18 button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-18 button span {
box-shadow: none;
border: 1px solid ButtonText;
}
}
```How this works
Two opposing inset shadows are the minimum. One light from the top-left, one dark from the bottom-right, both large and soft. A single inset shadow never reads as volume — that is the classic claymorphism failure, and Tailwind makes the pair visible on one line.
The squash composes because scale is its own property. active:scale-x-[0.96] active:scale-y-[0.9] sits alongside hover:-translate-y-[3px] without either overwriting the other — in a single transform string they would fight.
The icon chip is the same recipe at 2rem: two small inset shadows on a circle, rotating 90° on hover. Clay scales down cleanly as long as the blur radii scale with it.
Make it yours
--color-tb18-clayis the only colour to change; highlight and shade are derived tokens beside it.- Radius is the personality:
rounded-[2rem]is bubblegum,rounded-2xlapp-like,rounded-fulla clay ball. - Inflate by raising both inset blurs together — unequal values look wet rather than matte.
- Dark clay: keep the highlight token at 25–30% white or it turns plastic.
- The chip recipe scales to any 1–2rem element; reuse it for badges.
Gotchas — read before shipping
- Clay is inherently low-contrast. The label must be real ink, not a tint of the clay.
- Large inset blurs are expensive — don't put forty of these in a scrolling list with shadow transitions.
- Don't animate
rounded-*to fake the squash; scale is compositor-friendly and radius is not. - One inset shadow is not clay. Two, opposing, is the minimum.
- Forced-colors drops all of it by design — keep the border, or the button vanishes.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 113+ | 17.2+ | 128+ | 113+ |
linear() spring easing needs Chrome 113 / Safari 17.2 / Firefox 112, with the cubic-bezier fallback declared first in the token. Individual scale/translate utilities are well below Tailwind v4's floor.