08 / 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 Table CTA Button Hover Animation
Conversion-grade CTA choreography: hover any plan's button and colour sweeps in from the left, the padding breathes and an arrow slides in beside the label. Each button sets one arbitrary property — [--tpt08-fill:var(--color-tpt08-seed)] — and v4's before:bg-(--tpt08-fill) shorthand paints the sweep, so one class list powers three differently coloured CTAs.
Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49
Cruip · Affiliate link
The code
<section class="tpt-08 w-full min-h-svh grid place-items-center bg-tpt08-bg px-5 py-16 font-tpt08-sans text-tpt08-ink antialiased" aria-label="Pricing with animated call-to-action buttons">
<div class="grid w-full max-w-5xl justify-items-center gap-10">
<h2 class="text-center text-[clamp(26px,3.8vw,40px)] font-extrabold tracking-[-0.03em]">Grow your list, not your bill</h2>
<div class="grid w-full gap-5 md:grid-cols-3">
<article class="flex flex-col rounded-[20px] border border-tpt08-line bg-white p-7 [--tpt08-fill:var(--color-tpt08-seed)]">
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-mut uppercase">Seed</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$19</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>5k contacts</li><li>Email campaigns</li><li>Signup forms</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-tpt08-line px-5 text-sm font-bold text-tpt08-ink no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:border-(--tpt08-fill) hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:border-(--tpt08-fill) focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Seed</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
<article class="relative flex flex-col rounded-[20px] bg-white p-7 shadow-[0_20px_44px_-28px_var(--color-tpt08-bloom)] ring-2 ring-tpt08-bloom [--tpt08-fill:var(--color-tpt08-bloom)]">
<span class="absolute -top-3 left-7 rounded-full bg-tpt08-bloom px-3 py-1 text-[10.5px] font-bold tracking-[0.08em] text-white uppercase">Most popular</span>
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-bloom uppercase">Bloom</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$49</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>50k contacts</li><li>Automations</li><li>A/B testing</li><li>Landing pages</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-(--tpt08-fill) px-5 text-sm font-bold text-(--tpt08-fill) no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Bloom</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
<article class="flex flex-col rounded-[20px] border border-tpt08-line bg-white p-7 [--tpt08-fill:var(--color-tpt08-forest)]">
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-mut uppercase">Forest</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$129</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>Unlimited contacts</li><li>Multivariate testing</li><li>Dedicated IP</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-tpt08-line px-5 text-sm font-bold text-tpt08-ink no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:border-(--tpt08-fill) hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:border-(--tpt08-fill) focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Forest</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
</div>
<p aria-hidden="true" class="rounded-full border border-tpt08-line bg-white px-3.5 py-2 font-tpt08-mono text-[11.5px] text-tpt08-mut">[--tpt08-fill:…] · before:bg-(--tpt08-fill) · before:scale-x-0 → 100</p>
</div>
</section><section class="tpt-08 w-full min-h-svh grid place-items-center bg-tpt08-bg px-5 py-16 font-tpt08-sans text-tpt08-ink antialiased" aria-label="Pricing with animated call-to-action buttons">
<div class="grid w-full max-w-5xl justify-items-center gap-10">
<h2 class="text-center text-[clamp(26px,3.8vw,40px)] font-extrabold tracking-[-0.03em]">Grow your list, not your bill</h2>
<div class="grid w-full gap-5 md:grid-cols-3">
<article class="flex flex-col rounded-[20px] border border-tpt08-line bg-white p-7 [--tpt08-fill:var(--color-tpt08-seed)]">
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-mut uppercase">Seed</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$19</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>5k contacts</li><li>Email campaigns</li><li>Signup forms</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-tpt08-line px-5 text-sm font-bold text-tpt08-ink no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:border-(--tpt08-fill) hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:border-(--tpt08-fill) focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Seed</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
<article class="relative flex flex-col rounded-[20px] bg-white p-7 shadow-[0_20px_44px_-28px_var(--color-tpt08-bloom)] ring-2 ring-tpt08-bloom [--tpt08-fill:var(--color-tpt08-bloom)]">
<span class="absolute -top-3 left-7 rounded-full bg-tpt08-bloom px-3 py-1 text-[10.5px] font-bold tracking-[0.08em] text-white uppercase">Most popular</span>
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-bloom uppercase">Bloom</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$49</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>50k contacts</li><li>Automations</li><li>A/B testing</li><li>Landing pages</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-(--tpt08-fill) px-5 text-sm font-bold text-(--tpt08-fill) no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Bloom</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
<article class="flex flex-col rounded-[20px] border border-tpt08-line bg-white p-7 [--tpt08-fill:var(--color-tpt08-forest)]">
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-mut uppercase">Forest</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$129</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>Unlimited contacts</li><li>Multivariate testing</li><li>Dedicated IP</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-tpt08-line px-5 text-sm font-bold text-tpt08-ink no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:border-(--tpt08-fill) hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:border-(--tpt08-fill) focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Forest</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
</div>
<p aria-hidden="true" class="rounded-full border border-tpt08-line bg-white px-3.5 py-2 font-tpt08-mono text-[11.5px] text-tpt08-mut">[--tpt08-fill:…] · before:bg-(--tpt08-fill) · before:scale-x-0 → 100</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tpt08-bg: #f6f8f6;
--color-tpt08-bg: oklch(0.977 0.004 150);
--color-tpt08-ink: #181c19;
--color-tpt08-ink: oklch(0.22 0.01 150);
--color-tpt08-body: #464c47;
--color-tpt08-body: oklch(0.42 0.01 150);
--color-tpt08-mut: #636963;
--color-tpt08-mut: oklch(0.51 0.01 150);
--color-tpt08-line: #dde2dd;
--color-tpt08-line: oklch(0.9 0.008 150);
--color-tpt08-seed: #0f8a68;
--color-tpt08-seed: oklch(0.55 0.12 170);
--color-tpt08-bloom: #6a3ce0;
--color-tpt08-bloom: oklch(0.52 0.21 288);
--color-tpt08-forest: #1f5aa8;
--color-tpt08-forest: oklch(0.48 0.14 255);
--font-tpt08-sans: 'Manrope', system-ui, sans-serif;
--font-tpt08-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-08 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tpt08-bg: #f6f8f6;
--color-tpt08-bg: oklch(0.977 0.004 150);
--color-tpt08-ink: #181c19;
--color-tpt08-ink: oklch(0.22 0.01 150);
--color-tpt08-body: #464c47;
--color-tpt08-body: oklch(0.42 0.01 150);
--color-tpt08-mut: #636963;
--color-tpt08-mut: oklch(0.51 0.01 150);
--color-tpt08-line: #dde2dd;
--color-tpt08-line: oklch(0.9 0.008 150);
--color-tpt08-seed: #0f8a68;
--color-tpt08-seed: oklch(0.55 0.12 170);
--color-tpt08-bloom: #6a3ce0;
--color-tpt08-bloom: oklch(0.52 0.21 288);
--color-tpt08-forest: #1f5aa8;
--color-tpt08-forest: oklch(0.48 0.14 255);
--font-tpt08-sans: 'Manrope', system-ui, sans-serif;
--font-tpt08-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-08 {
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-tpt08-bg: #f6f8f6;
--color-tpt08-bg: oklch(0.977 0.004 150);
--color-tpt08-ink: #181c19;
--color-tpt08-ink: oklch(0.22 0.01 150);
--color-tpt08-body: #464c47;
--color-tpt08-body: oklch(0.42 0.01 150);
--color-tpt08-mut: #636963;
--color-tpt08-mut: oklch(0.51 0.01 150);
--color-tpt08-line: #dde2dd;
--color-tpt08-line: oklch(0.9 0.008 150);
--color-tpt08-seed: #0f8a68;
--color-tpt08-seed: oklch(0.55 0.12 170);
--color-tpt08-bloom: #6a3ce0;
--color-tpt08-bloom: oklch(0.52 0.21 288);
--color-tpt08-forest: #1f5aa8;
--color-tpt08-forest: oklch(0.48 0.14 255);
--font-tpt08-sans: 'Manrope', system-ui, sans-serif;
--font-tpt08-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-08 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tpt08-bg: #f6f8f6;
--color-tpt08-bg: oklch(0.977 0.004 150);
--color-tpt08-ink: #181c19;
--color-tpt08-ink: oklch(0.22 0.01 150);
--color-tpt08-body: #464c47;
--color-tpt08-body: oklch(0.42 0.01 150);
--color-tpt08-mut: #636963;
--color-tpt08-mut: oklch(0.51 0.01 150);
--color-tpt08-line: #dde2dd;
--color-tpt08-line: oklch(0.9 0.008 150);
--color-tpt08-seed: #0f8a68;
--color-tpt08-seed: oklch(0.55 0.12 170);
--color-tpt08-bloom: #6a3ce0;
--color-tpt08-bloom: oklch(0.52 0.21 288);
--color-tpt08-forest: #1f5aa8;
--color-tpt08-forest: oklch(0.48 0.14 255);
--font-tpt08-sans: 'Manrope', system-ui, sans-serif;
--font-tpt08-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-08 {
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=Manrope:wght@400..800&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=Manrope:wght@400..800&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="--fill:…"became an arbitrary property utility[--tpt08-fill:…]on the card, read everywhere with v4'sbg-(--tpt08-fill)shorthand. - Six
:hover, :focus-visibleselector pairs became pairedhover:/focus-visible:utilities, and the arrow's rules becamegroup-hover/cta:/group-focus-visible/cta:. - UI upgrade from the CSS original: the variable now lives on the card, so the checkmarks share the plan colour too; the popular plan's button is outlined in its colour at rest so it reads as primary before hover.
- UI upgrade:
active:scale-[.98]press feedback, 48px buttons (was 45), fill colours darkened so white labels clear 4.5:1 on all three.
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 Table CTA Button Hover Animation
Source: https://codefronts.com/components/tailwind-css-pricing-tables/tailwind-pricing-table-cta-button-hover-animation/
Conversion-grade CTA choreography: hover any plan's button and colour sweeps in from the left, the padding breathes and an arrow slides in beside the label. Each button sets one arbitrary property — [--tpt08-fill:var(--color-tpt08-seed)] — and v4's before:bg-(--tpt08-fill) shorthand paints the sweep, so one class list powers three differently coloured CTAs.
## HTML
```html
<section class="tpt-08 w-full min-h-svh grid place-items-center bg-tpt08-bg px-5 py-16 font-tpt08-sans text-tpt08-ink antialiased" aria-label="Pricing with animated call-to-action buttons">
<div class="grid w-full max-w-5xl justify-items-center gap-10">
<h2 class="text-center text-[clamp(26px,3.8vw,40px)] font-extrabold tracking-[-0.03em]">Grow your list, not your bill</h2>
<div class="grid w-full gap-5 md:grid-cols-3">
<article class="flex flex-col rounded-[20px] border border-tpt08-line bg-white p-7 [--tpt08-fill:var(--color-tpt08-seed)]">
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-mut uppercase">Seed</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$19</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>5k contacts</li><li>Email campaigns</li><li>Signup forms</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-tpt08-line px-5 text-sm font-bold text-tpt08-ink no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:border-(--tpt08-fill) hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:border-(--tpt08-fill) focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Seed</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
<article class="relative flex flex-col rounded-[20px] bg-white p-7 shadow-[0_20px_44px_-28px_var(--color-tpt08-bloom)] ring-2 ring-tpt08-bloom [--tpt08-fill:var(--color-tpt08-bloom)]">
<span class="absolute -top-3 left-7 rounded-full bg-tpt08-bloom px-3 py-1 text-[10.5px] font-bold tracking-[0.08em] text-white uppercase">Most popular</span>
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-bloom uppercase">Bloom</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$49</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>50k contacts</li><li>Automations</li><li>A/B testing</li><li>Landing pages</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-(--tpt08-fill) px-5 text-sm font-bold text-(--tpt08-fill) no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Bloom</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
<article class="flex flex-col rounded-[20px] border border-tpt08-line bg-white p-7 [--tpt08-fill:var(--color-tpt08-forest)]">
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-mut uppercase">Forest</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$129</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>Unlimited contacts</li><li>Multivariate testing</li><li>Dedicated IP</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-tpt08-line px-5 text-sm font-bold text-tpt08-ink no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:border-(--tpt08-fill) hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:border-(--tpt08-fill) focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Forest</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
</div>
<p aria-hidden="true" class="rounded-full border border-tpt08-line bg-white px-3.5 py-2 font-tpt08-mono text-[11.5px] text-tpt08-mut">[--tpt08-fill:…] · before:bg-(--tpt08-fill) · before:scale-x-0 → 100</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tpt08-bg: #f6f8f6;
--color-tpt08-bg: oklch(0.977 0.004 150);
--color-tpt08-ink: #181c19;
--color-tpt08-ink: oklch(0.22 0.01 150);
--color-tpt08-body: #464c47;
--color-tpt08-body: oklch(0.42 0.01 150);
--color-tpt08-mut: #636963;
--color-tpt08-mut: oklch(0.51 0.01 150);
--color-tpt08-line: #dde2dd;
--color-tpt08-line: oklch(0.9 0.008 150);
--color-tpt08-seed: #0f8a68;
--color-tpt08-seed: oklch(0.55 0.12 170);
--color-tpt08-bloom: #6a3ce0;
--color-tpt08-bloom: oklch(0.52 0.21 288);
--color-tpt08-forest: #1f5aa8;
--color-tpt08-forest: oklch(0.48 0.14 255);
--font-tpt08-sans: 'Manrope', system-ui, sans-serif;
--font-tpt08-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-08 {
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 Pricing Table CTA Button Hover Animation
Source: https://codefronts.com/components/tailwind-css-pricing-tables/tailwind-pricing-table-cta-button-hover-animation/
Conversion-grade CTA choreography: hover any plan's button and colour sweeps in from the left, the padding breathes and an arrow slides in beside the label. Each button sets one arbitrary property — [--tpt08-fill:var(--color-tpt08-seed)] — and v4's before:bg-(--tpt08-fill) shorthand paints the sweep, so one class list powers three differently coloured CTAs.
## HTML
```html
<section class="tpt-08 w-full min-h-svh grid place-items-center bg-tpt08-bg px-5 py-16 font-tpt08-sans text-tpt08-ink antialiased" aria-label="Pricing with animated call-to-action buttons">
<div class="grid w-full max-w-5xl justify-items-center gap-10">
<h2 class="text-center text-[clamp(26px,3.8vw,40px)] font-extrabold tracking-[-0.03em]">Grow your list, not your bill</h2>
<div class="grid w-full gap-5 md:grid-cols-3">
<article class="flex flex-col rounded-[20px] border border-tpt08-line bg-white p-7 [--tpt08-fill:var(--color-tpt08-seed)]">
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-mut uppercase">Seed</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$19</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>5k contacts</li><li>Email campaigns</li><li>Signup forms</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-tpt08-line px-5 text-sm font-bold text-tpt08-ink no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:border-(--tpt08-fill) hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:border-(--tpt08-fill) focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Seed</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
<article class="relative flex flex-col rounded-[20px] bg-white p-7 shadow-[0_20px_44px_-28px_var(--color-tpt08-bloom)] ring-2 ring-tpt08-bloom [--tpt08-fill:var(--color-tpt08-bloom)]">
<span class="absolute -top-3 left-7 rounded-full bg-tpt08-bloom px-3 py-1 text-[10.5px] font-bold tracking-[0.08em] text-white uppercase">Most popular</span>
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-bloom uppercase">Bloom</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$49</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>50k contacts</li><li>Automations</li><li>A/B testing</li><li>Landing pages</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-(--tpt08-fill) px-5 text-sm font-bold text-(--tpt08-fill) no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Bloom</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
<article class="flex flex-col rounded-[20px] border border-tpt08-line bg-white p-7 [--tpt08-fill:var(--color-tpt08-forest)]">
<h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt08-mut uppercase">Forest</h3>
<p class="mt-3 text-[44px] leading-none font-extrabold tracking-[-0.035em]">$129</p>
<span class="mt-1.5 text-[13px] text-tpt08-mut">per month</span>
<ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt08-body *:flex *:gap-2.5 *:before:font-bold *:before:text-(--tpt08-fill) *:before:content-['✓']"><li>Unlimited contacts</li><li>Multivariate testing</li><li>Dedicated IP</li></ul>
<a href="#" class="group/cta relative flex min-h-12 items-center justify-center overflow-hidden rounded-xl border-[1.5px] border-tpt08-line px-5 text-sm font-bold text-tpt08-ink no-underline transition-[color,border-color,padding,scale] duration-300 before:absolute before:inset-0 before:origin-left before:scale-x-0 before:bg-(--tpt08-fill) before:transition-transform before:duration-350 before:ease-[cubic-bezier(.6,0,.2,1)] before:content-[''] hover:border-(--tpt08-fill) hover:px-6 hover:text-white hover:before:scale-x-100 focus-visible:border-(--tpt08-fill) focus-visible:text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-(--tpt08-fill) focus-visible:before:scale-x-100 active:scale-[.98] motion-reduce:transition-none motion-reduce:before:transition-none"><span class="relative">Choose Forest</span><span aria-hidden="true" class="relative inline-block w-0 translate-x-2 opacity-0 transition-[width,opacity,translate] duration-300 group-hover/cta:w-5 group-hover/cta:translate-x-1.5 group-hover/cta:opacity-100 group-focus-visible/cta:w-5 group-focus-visible/cta:translate-x-1.5 group-focus-visible/cta:opacity-100">→</span></a>
</article>
</div>
<p aria-hidden="true" class="rounded-full border border-tpt08-line bg-white px-3.5 py-2 font-tpt08-mono text-[11.5px] text-tpt08-mut">[--tpt08-fill:…] · before:bg-(--tpt08-fill) · before:scale-x-0 → 100</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tpt08-bg: #f6f8f6;
--color-tpt08-bg: oklch(0.977 0.004 150);
--color-tpt08-ink: #181c19;
--color-tpt08-ink: oklch(0.22 0.01 150);
--color-tpt08-body: #464c47;
--color-tpt08-body: oklch(0.42 0.01 150);
--color-tpt08-mut: #636963;
--color-tpt08-mut: oklch(0.51 0.01 150);
--color-tpt08-line: #dde2dd;
--color-tpt08-line: oklch(0.9 0.008 150);
--color-tpt08-seed: #0f8a68;
--color-tpt08-seed: oklch(0.55 0.12 170);
--color-tpt08-bloom: #6a3ce0;
--color-tpt08-bloom: oklch(0.52 0.21 288);
--color-tpt08-forest: #1f5aa8;
--color-tpt08-forest: oklch(0.48 0.14 255);
--font-tpt08-sans: 'Manrope', system-ui, sans-serif;
--font-tpt08-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */
.tpt-08 {
width: 100%;
min-height: 100svh;
}
```How this works
A variable per plan, one ruleset. The card sets [--tpt08-fill:var(--color-tpt08-bloom)]; everything inside reads it with v4's parenthesis shorthand:
before:bg-(--tpt08-fill) hover:border-(--tpt08-fill)
*:before:text-(--tpt08-fill)Fill by scale, not size. The sweep is a before: layer scaled from scale-x-0 with origin-left; the label sits above it via relative.
The arrow starts at w-0 opacity-0 translate-x-2 and grows to w-5 — a tiny, contained layout tween that keeps the label-plus-arrow pair optically centred.
Make it yours
- Per-plan colour: change the
[--tpt08-fill:…]on each card. - Reverse the sweep:
before:origin-right. - Swap the arrow for a cart icon — keep
aria-hidden. - Selected state: add the hover utilities under
aria-[current=true]:for a sticky choice.
Gotchas — read before shipping
- The label must be
relative(orz-10) or the fill layer paints over it. - Check contrast in both states: dark ink before the sweep, white after.
- Keep
overflow-hiddenon the button so the scaled fill respects the radius.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Plain transforms and custom properties; the floor is Tailwind v4's sheet.