09 / 21
All 21 in 21 Tailwind CSS Pricing Tables
- 01Tailwind CSS Pricing Table with Monthly / Annual Toggle
- 02Tailwind Pricing Table with Currency Switcher (USD, GBP, EUR, AUD)
- 03Tailwind CSS Pricing Comparison Table with Expandable Features
- 04Tailwind Dark Mode Pricing Cards with Light / Dark Toggle
- 05Tailwind Pricing Cards with Hover Scale Effect
- 06Tailwind "Most Popular" Pricing Card with Animated Border Beam
- 07Tailwind Pricing Cards with Animated Discount Badges
- 08Tailwind Pricing Table CTA Button Hover Animation
- 09Tailwind Pricing Cards with Color-Changing Hover Themes
- 10Tailwind CSS 3D Flip Pricing Cards
- 11Tailwind Pricing Slider Calculator for Per-Seat Pricing
- 12Tailwind Tabbed Pricing Table for Multiple Products
- 13Tailwind Pricing Cards with Usage Meters & Progress Bars
- 14Tailwind Bundle Pricing Calculator with Checkboxes
- 15Glassmorphism Pricing Cards in Tailwind CSS
- 16Tailwind Pricing Card with Animated Gradient Border on Hover
- 17Tailwind Pricing Cards with Corner Ribbon & Bookmark Banner
- 18Neumorphic Pricing Table in Tailwind CSS (Soft UI)
- 19Mobile Swipe Pricing Carousel with Tailwind Scroll Snap
- 20Responsive Tailwind Pricing Table that Stacks into an Accordion
- 21Tailwind Pricing Cards with Skeleton Loading Shimmer
Tailwind Pricing Cards with Color-Changing Hover Themes
Each tier carries its own hue. Hover a card and its colour floods the plan name, checkmarks, divider and CTA — and the whole section's backdrop tints to match. Every accent is derived as oklch(L var(--tpt09-c) var(--tpt09-h)) in arbitrary utilities; registering the chroma and the wash hue with @property means the colour itself glides, not just the properties that use it.
Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49
Cruip · Affiliate link
The code
<section class="tpt-09 group/p relative isolate w-full min-h-svh grid place-items-center overflow-hidden bg-tpt09-bg px-5 py-16 font-tpt09-sans text-tpt09-ink antialiased [transition:--tpt09-wash_700ms] has-[[data-h='160']:hover]:[--tpt09-wash:160] has-[[data-h='160']:focus-within]:[--tpt09-wash:160] has-[[data-h='280']:hover]:[--tpt09-wash:280] has-[[data-h='280']:focus-within]:[--tpt09-wash:280] has-[[data-h='40']:hover]:[--tpt09-wash:40] has-[[data-h='40']:focus-within]:[--tpt09-wash:40]" aria-label="Pricing cards with per-plan colour themes">
<div aria-hidden="true" class="pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(60%_80%_at_50%_110%,oklch(0.45_0.16_var(--tpt09-wash)/0.45),transparent_70%)] opacity-0 transition-opacity duration-700 group-has-[article:hover]/p:opacity-100 group-has-[article:focus-within]/p:opacity-100"></div>
<div class="grid w-full max-w-5xl justify-items-center gap-10">
<h2 class="text-center text-[clamp(26px,3.8vw,40px)] font-bold tracking-[-0.03em]">A plan for every palette</h2>
<div class="grid w-full gap-5 md:grid-cols-3">
<article data-h="160" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:160] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Mint</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$12<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Personal licence</li><li>20 exports / month</li><li>1080p renders</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Mint</a>
</article>
<article data-h="280" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:280] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Violet</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$32<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Commercial licence</li><li>Unlimited exports</li><li>4K renders</li><li>Brand kits</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Violet</a>
</article>
<article data-h="40" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:40] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Amber</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$79<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Team licence</li><li>Shared libraries</li><li>8K renders</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Amber</a>
</article>
</div>
<p aria-hidden="true" class="rounded-full border border-white/12 px-3.5 py-2 font-tpt09-mono text-[11.5px] text-tpt09-mut">@property --tpt09-c · oklch(L var(--c) var(--h)) · has-[[data-h]:hover]:</p>
</div>
</section><section class="tpt-09 group/p relative isolate w-full min-h-svh grid place-items-center overflow-hidden bg-tpt09-bg px-5 py-16 font-tpt09-sans text-tpt09-ink antialiased [transition:--tpt09-wash_700ms] has-[[data-h='160']:hover]:[--tpt09-wash:160] has-[[data-h='160']:focus-within]:[--tpt09-wash:160] has-[[data-h='280']:hover]:[--tpt09-wash:280] has-[[data-h='280']:focus-within]:[--tpt09-wash:280] has-[[data-h='40']:hover]:[--tpt09-wash:40] has-[[data-h='40']:focus-within]:[--tpt09-wash:40]" aria-label="Pricing cards with per-plan colour themes">
<div aria-hidden="true" class="pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(60%_80%_at_50%_110%,oklch(0.45_0.16_var(--tpt09-wash)/0.45),transparent_70%)] opacity-0 transition-opacity duration-700 group-has-[article:hover]/p:opacity-100 group-has-[article:focus-within]/p:opacity-100"></div>
<div class="grid w-full max-w-5xl justify-items-center gap-10">
<h2 class="text-center text-[clamp(26px,3.8vw,40px)] font-bold tracking-[-0.03em]">A plan for every palette</h2>
<div class="grid w-full gap-5 md:grid-cols-3">
<article data-h="160" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:160] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Mint</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$12<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Personal licence</li><li>20 exports / month</li><li>1080p renders</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Mint</a>
</article>
<article data-h="280" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:280] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Violet</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$32<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Commercial licence</li><li>Unlimited exports</li><li>4K renders</li><li>Brand kits</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Violet</a>
</article>
<article data-h="40" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:40] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Amber</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$79<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Team licence</li><li>Shared libraries</li><li>8K renders</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Amber</a>
</article>
</div>
<p aria-hidden="true" class="rounded-full border border-white/12 px-3.5 py-2 font-tpt09-mono text-[11.5px] text-tpt09-mut">@property --tpt09-c · oklch(L var(--c) var(--h)) · has-[[data-h]:hover]:</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tpt09-bg: #0f0f13;
--color-tpt09-bg: oklch(0.17 0.008 280);
--color-tpt09-card: #17171d;
--color-tpt09-card: oklch(0.215 0.01 280);
--color-tpt09-ink: #ecedf2;
--color-tpt09-ink: oklch(0.95 0.006 280);
--color-tpt09-body: #c0c3d0;
--color-tpt09-body: oklch(0.83 0.015 280);
--color-tpt09-mut: #9296a6;
--color-tpt09-mut: oklch(0.69 0.018 280);
--font-tpt09-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tpt09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-09 {
width: 100%;
min-height: 100svh;
}
/* Registered so they interpolate: chroma lifts on hover, wash hue sweeps between cards. */
@property --tpt09-c {
syntax: '<number>';
initial-value: 0.02;
inherits: true;
}
@property --tpt09-wash {
syntax: '<number>';
initial-value: 280;
inherits: true;
}@import "tailwindcss";
@theme {
--color-tpt09-bg: #0f0f13;
--color-tpt09-bg: oklch(0.17 0.008 280);
--color-tpt09-card: #17171d;
--color-tpt09-card: oklch(0.215 0.01 280);
--color-tpt09-ink: #ecedf2;
--color-tpt09-ink: oklch(0.95 0.006 280);
--color-tpt09-body: #c0c3d0;
--color-tpt09-body: oklch(0.83 0.015 280);
--color-tpt09-mut: #9296a6;
--color-tpt09-mut: oklch(0.69 0.018 280);
--font-tpt09-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tpt09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-09 {
width: 100%;
min-height: 100svh;
}
/* Registered so they interpolate: chroma lifts on hover, wash hue sweeps between cards. */
@property --tpt09-c {
syntax: '<number>';
initial-value: 0.02;
inherits: true;
}
@property --tpt09-wash {
syntax: '<number>';
initial-value: 280;
inherits: true;
}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-tpt09-bg: #0f0f13;
--color-tpt09-bg: oklch(0.17 0.008 280);
--color-tpt09-card: #17171d;
--color-tpt09-card: oklch(0.215 0.01 280);
--color-tpt09-ink: #ecedf2;
--color-tpt09-ink: oklch(0.95 0.006 280);
--color-tpt09-body: #c0c3d0;
--color-tpt09-body: oklch(0.83 0.015 280);
--color-tpt09-mut: #9296a6;
--color-tpt09-mut: oklch(0.69 0.018 280);
--font-tpt09-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tpt09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-09 {
width: 100%;
min-height: 100svh;
}
/* Registered so they interpolate: chroma lifts on hover, wash hue sweeps between cards. */
@property --tpt09-c {
syntax: '<number>';
initial-value: 0.02;
inherits: true;
}
@property --tpt09-wash {
syntax: '<number>';
initial-value: 280;
inherits: true;
}@import "tailwindcss";
@theme {
--color-tpt09-bg: #0f0f13;
--color-tpt09-bg: oklch(0.17 0.008 280);
--color-tpt09-card: #17171d;
--color-tpt09-card: oklch(0.215 0.01 280);
--color-tpt09-ink: #ecedf2;
--color-tpt09-ink: oklch(0.95 0.006 280);
--color-tpt09-body: #c0c3d0;
--color-tpt09-body: oklch(0.83 0.015 280);
--color-tpt09-mut: #9296a6;
--color-tpt09-mut: oklch(0.69 0.018 280);
--font-tpt09-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tpt09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-09 {
width: 100%;
min-height: 100svh;
}
/* Registered so they interpolate: chroma lifts on hover, wash hue sweeps between cards. */
@property --tpt09-c {
syntax: '<number>';
initial-value: 0.02;
inherits: true;
}
@property --tpt09-wash {
syntax: '<number>';
initial-value: 280;
inherits: true;
}<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=Space+Grotesk:wght@400..700&family=JetBrains+Mono:wght@400;500&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=Space+Grotesk:wght@400..700&family=JetBrains+Mono:wght@400;500&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The inline
style="--h:160"became[--tpt09-h:160], and the brittle[style*="--h:160"]attribute-substring selectors becamedata-h+has-[[data-h='160']:hover]:on the section. - Every
oklch(… var(--h))derivation ported unchanged into arbitrary colour utilities;calc()needs no spaces, so no underscores. - UI upgrade from the CSS original:
--tpt09-cand--tpt09-washare now registered with@property, so saturation glides and the backdrop hue sweeps between cards instead of snapping. - UI upgrade: the CTA shows its hue at rest (was near-grey), the wash also responds to keyboard focus, plan names brightened from L 0.72 to 0.8 and muted price copy from
#878b9cto 5.9:1.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Pricing Cards with Color-Changing Hover Themes
Source: https://codefronts.com/components/tailwind-css-pricing-tables/tailwind-pricing-cards-color-changing-hover/
Each tier carries its own hue. Hover a card and its colour floods the plan name, checkmarks, divider and CTA — and the whole section's backdrop tints to match. Every accent is derived as oklch(L var(--tpt09-c) var(--tpt09-h)) in arbitrary utilities; registering the chroma and the wash hue with @property means the colour itself glides, not just the properties that use it.
## HTML
```html
<section class="tpt-09 group/p relative isolate w-full min-h-svh grid place-items-center overflow-hidden bg-tpt09-bg px-5 py-16 font-tpt09-sans text-tpt09-ink antialiased [transition:--tpt09-wash_700ms] has-[[data-h='160']:hover]:[--tpt09-wash:160] has-[[data-h='160']:focus-within]:[--tpt09-wash:160] has-[[data-h='280']:hover]:[--tpt09-wash:280] has-[[data-h='280']:focus-within]:[--tpt09-wash:280] has-[[data-h='40']:hover]:[--tpt09-wash:40] has-[[data-h='40']:focus-within]:[--tpt09-wash:40]" aria-label="Pricing cards with per-plan colour themes">
<div aria-hidden="true" class="pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(60%_80%_at_50%_110%,oklch(0.45_0.16_var(--tpt09-wash)/0.45),transparent_70%)] opacity-0 transition-opacity duration-700 group-has-[article:hover]/p:opacity-100 group-has-[article:focus-within]/p:opacity-100"></div>
<div class="grid w-full max-w-5xl justify-items-center gap-10">
<h2 class="text-center text-[clamp(26px,3.8vw,40px)] font-bold tracking-[-0.03em]">A plan for every palette</h2>
<div class="grid w-full gap-5 md:grid-cols-3">
<article data-h="160" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:160] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Mint</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$12<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Personal licence</li><li>20 exports / month</li><li>1080p renders</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Mint</a>
</article>
<article data-h="280" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:280] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Violet</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$32<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Commercial licence</li><li>Unlimited exports</li><li>4K renders</li><li>Brand kits</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Violet</a>
</article>
<article data-h="40" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:40] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Amber</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$79<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Team licence</li><li>Shared libraries</li><li>8K renders</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Amber</a>
</article>
</div>
<p aria-hidden="true" class="rounded-full border border-white/12 px-3.5 py-2 font-tpt09-mono text-[11.5px] text-tpt09-mut">@property --tpt09-c · oklch(L var(--c) var(--h)) · has-[[data-h]:hover]:</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tpt09-bg: #0f0f13;
--color-tpt09-bg: oklch(0.17 0.008 280);
--color-tpt09-card: #17171d;
--color-tpt09-card: oklch(0.215 0.01 280);
--color-tpt09-ink: #ecedf2;
--color-tpt09-ink: oklch(0.95 0.006 280);
--color-tpt09-body: #c0c3d0;
--color-tpt09-body: oklch(0.83 0.015 280);
--color-tpt09-mut: #9296a6;
--color-tpt09-mut: oklch(0.69 0.018 280);
--font-tpt09-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tpt09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-09 {
width: 100%;
min-height: 100svh;
}
/* Registered so they interpolate: chroma lifts on hover, wash hue sweeps between cards. */
@property --tpt09-c {
syntax: '<number>';
initial-value: 0.02;
inherits: true;
}
@property --tpt09-wash {
syntax: '<number>';
initial-value: 280;
inherits: true;
}
```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 Pricing Cards with Color-Changing Hover Themes
Source: https://codefronts.com/components/tailwind-css-pricing-tables/tailwind-pricing-cards-color-changing-hover/
Each tier carries its own hue. Hover a card and its colour floods the plan name, checkmarks, divider and CTA — and the whole section's backdrop tints to match. Every accent is derived as oklch(L var(--tpt09-c) var(--tpt09-h)) in arbitrary utilities; registering the chroma and the wash hue with @property means the colour itself glides, not just the properties that use it.
## HTML
```html
<section class="tpt-09 group/p relative isolate w-full min-h-svh grid place-items-center overflow-hidden bg-tpt09-bg px-5 py-16 font-tpt09-sans text-tpt09-ink antialiased [transition:--tpt09-wash_700ms] has-[[data-h='160']:hover]:[--tpt09-wash:160] has-[[data-h='160']:focus-within]:[--tpt09-wash:160] has-[[data-h='280']:hover]:[--tpt09-wash:280] has-[[data-h='280']:focus-within]:[--tpt09-wash:280] has-[[data-h='40']:hover]:[--tpt09-wash:40] has-[[data-h='40']:focus-within]:[--tpt09-wash:40]" aria-label="Pricing cards with per-plan colour themes">
<div aria-hidden="true" class="pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(60%_80%_at_50%_110%,oklch(0.45_0.16_var(--tpt09-wash)/0.45),transparent_70%)] opacity-0 transition-opacity duration-700 group-has-[article:hover]/p:opacity-100 group-has-[article:focus-within]/p:opacity-100"></div>
<div class="grid w-full max-w-5xl justify-items-center gap-10">
<h2 class="text-center text-[clamp(26px,3.8vw,40px)] font-bold tracking-[-0.03em]">A plan for every palette</h2>
<div class="grid w-full gap-5 md:grid-cols-3">
<article data-h="160" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:160] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Mint</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$12<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Personal licence</li><li>20 exports / month</li><li>1080p renders</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Mint</a>
</article>
<article data-h="280" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:280] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Violet</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$32<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Commercial licence</li><li>Unlimited exports</li><li>4K renders</li><li>Brand kits</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Violet</a>
</article>
<article data-h="40" class="flex flex-col gap-4 rounded-[20px] border-[1.5px] border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))] bg-tpt09-card p-7 [transition:--tpt09-c_500ms,translate_500ms] [--tpt09-h:40] hover:-translate-y-1.5 hover:[--tpt09-c:0.17] focus-within:[--tpt09-c:0.17] motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 class="text-[13px] font-bold tracking-[0.1em] text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] uppercase">Amber</h3>
<p class="text-[44px] leading-none font-bold tracking-[-0.035em]">$79<small class="text-[15px] font-medium tracking-normal text-tpt09-mut">/mo</small></p>
<hr class="h-[1.5px] border-0 bg-[oklch(0.45_calc(var(--tpt09-c)*1.6)_var(--tpt09-h))]">
<ul class="grid flex-1 content-start gap-2.5 text-sm text-tpt09-body *:flex *:gap-2.5 *:before:font-bold *:before:text-[oklch(0.8_var(--tpt09-c)_var(--tpt09-h))] *:before:content-['✓']"><li>Team licence</li><li>Shared libraries</li><li>8K renders</li></ul>
<a href="#" class="grid min-h-11 place-items-center rounded-xl bg-[oklch(0.34_calc(var(--tpt09-c)*1.2)_var(--tpt09-h))] text-sm font-bold text-white no-underline focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[oklch(0.8_0.15_var(--tpt09-h))]">Get Amber</a>
</article>
</div>
<p aria-hidden="true" class="rounded-full border border-white/12 px-3.5 py-2 font-tpt09-mono text-[11.5px] text-tpt09-mut">@property --tpt09-c · oklch(L var(--c) var(--h)) · has-[[data-h]:hover]:</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tpt09-bg: #0f0f13;
--color-tpt09-bg: oklch(0.17 0.008 280);
--color-tpt09-card: #17171d;
--color-tpt09-card: oklch(0.215 0.01 280);
--color-tpt09-ink: #ecedf2;
--color-tpt09-ink: oklch(0.95 0.006 280);
--color-tpt09-body: #c0c3d0;
--color-tpt09-body: oklch(0.83 0.015 280);
--color-tpt09-mut: #9296a6;
--color-tpt09-mut: oklch(0.69 0.018 280);
--font-tpt09-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tpt09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-09 {
width: 100%;
min-height: 100svh;
}
/* Registered so they interpolate: chroma lifts on hover, wash hue sweeps between cards. */
@property --tpt09-c {
syntax: '<number>';
initial-value: 0.02;
inherits: true;
}
@property --tpt09-wash {
syntax: '<number>';
initial-value: 280;
inherits: true;
}
```How this works
Derived colour in utilities. Arbitrary values accept calc() and var() directly:
border-[oklch(0.4_calc(var(--tpt09-c)*2)_var(--tpt09-h))]
text-[oklch(0.78_var(--tpt09-c)_var(--tpt09-h))]Registered chroma. The CSS original relied on each derived property transitioning separately (and gradients didn't). Registering --tpt09-c as a <number> lets the card transition the variable once: hover:[--tpt09-c:0.17]. Everything that reads it — including the radial wash — updates per frame.
The wash is an aria-hidden layer whose hue is the section's --tpt09-wash; hovering Violet sets it to 280, moving to Amber sweeps it through the spectrum to 40.
Make it yours
- Add a tier with one
[--tpt09-h:…]and a matchinghas-[[data-h='…']:hover]:on the section. - Saturation lift: the
hover:[--tpt09-c:0.17]value. - Calmer page: delete the wash layer — cards still shift individually.
- Brand hexes: swap the oklch() derivations for
color-mix(in oklch, var(--brand) …).
Gotchas — read before shipping
- Registered properties need
inherits:truehere so card children read the animated value. - Yellows and cyans need a higher lightness for text than blues — check each hue's contrast.
- The wash must stay
pointer-events-noneand behind the grid (isolate+-z-10).
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
@property + oklch() + :has(); without @property the colours snap instead of gliding.