Pure TailwindMIT licensed

Tailwind Pricing Cards with Hover Scale Effect

The classic conversion micro-interaction: hover or keyboard-focus any tier and it lifts, scales and deepens its shadow while its siblings ease back and desaturate. The sibling logic is v4's variant stacking — group-has-[article:hover]/g:not-hover:scale-96 — read left to right as “when any card in the grid is hovered, and this one isn't”.

Live Demo
Plain CSSTailwind v4
Try it

Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49

Cruip · Affiliate link

Browse Cruip templates

The code

<section class="tpt-05 w-full min-h-svh grid place-items-center bg-tpt05-bg bg-[radial-gradient(70%_50%_at_50%_100%,var(--color-tpt05-glow),transparent)] px-5 py-16 font-tpt05-sans text-tpt05-ink antialiased" aria-label="Pricing cards with focus hover effect">
  <div class="grid w-full max-w-5xl justify-items-center gap-11">
    <h2 class="text-center text-[clamp(26px,3.8vw,40px)] font-extrabold tracking-[-0.03em]">Pick your pace</h2>
    <div class="group/g grid w-full gap-6 md:grid-cols-3">
      <article class="relative flex flex-col rounded-3xl border border-tpt05-line bg-white p-8 transition-[translate,scale,filter,opacity] duration-350 ease-[cubic-bezier(.3,1.2,.3,1)] will-change-transform after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:opacity-0 after:shadow-[0_30px_60px_-22px_var(--color-tpt05-acc)] after:transition-opacity after:duration-350 after:content-[''] hover:z-10 hover:-translate-y-2.5 hover:scale-105 hover:after:opacity-60 focus-within:z-10 focus-within:-translate-y-2.5 focus-within:scale-105 focus-within:after:opacity-60 group-has-[article:hover]/g:not-hover:scale-96 group-has-[article:hover]/g:not-hover:opacity-75 group-has-[article:hover]/g:not-hover:saturate-50 motion-reduce:transition-none motion-reduce:hover:translate-y-0 motion-reduce:hover:scale-100">
        <h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt05-mut uppercase">Lite</h3>
        <p class="mt-3 text-[46px] leading-none font-extrabold tracking-[-0.035em]">$15<small class="text-[15px] font-semibold tracking-normal text-tpt05-mut"> / month</small></p>
        <ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt05-body *:flex *:gap-2.5 *:before:font-bold *:before:text-tpt05-acc *:before:content-['✓']"><li>2 seats</li><li>Weekly reports</li><li>Email support</li></ul>
        <a href="#" class="grid min-h-11 place-items-center rounded-xl bg-tpt05-ink text-sm font-bold text-white no-underline transition-colors hover:bg-tpt05-acc focus-visible:bg-tpt05-acc focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tpt05-acc">Select Lite</a>
      </article>
      <article class="relative flex flex-col rounded-3xl border border-tpt05-acc/40 bg-white p-8 transition-[translate,scale,filter,opacity] duration-350 ease-[cubic-bezier(.3,1.2,.3,1)] will-change-transform after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:opacity-35 after:shadow-[0_30px_60px_-22px_var(--color-tpt05-acc)] after:transition-opacity after:duration-350 after:content-[''] md:scale-[1.03] hover:z-10 hover:-translate-y-2.5 hover:scale-105 hover:after:opacity-60 focus-within:z-10 focus-within:-translate-y-2.5 focus-within:scale-105 focus-within:after:opacity-60 group-has-[article:hover]/g:not-hover:scale-96 group-has-[article:hover]/g:not-hover:opacity-75 group-has-[article:hover]/g:not-hover:saturate-50 group-has-[article:hover]/g:not-hover:after:opacity-0 motion-reduce:transition-none motion-reduce:hover:translate-y-0 motion-reduce:hover:scale-100">
        <span class="absolute -top-3 left-8 rounded-full bg-tpt05-acc px-3 py-1 text-[10.5px] font-bold tracking-[0.08em] text-white uppercase">Recommended</span>
        <h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt05-acc-ink uppercase">Growth</h3>
        <p class="mt-3 text-[46px] leading-none font-extrabold tracking-[-0.035em]">$39<small class="text-[15px] font-semibold tracking-normal text-tpt05-mut"> / month</small></p>
        <ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt05-body *:flex *:gap-2.5 *:before:font-bold *:before:text-tpt05-acc *:before:content-['✓']"><li>10 seats</li><li>Daily reports</li><li>200+ integrations</li><li>Live chat support</li></ul>
        <a href="#" class="grid min-h-11 place-items-center rounded-xl bg-tpt05-acc text-sm font-bold text-white no-underline transition-colors hover:bg-tpt05-acc-ink focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tpt05-acc">Select Growth</a>
      </article>
      <article class="relative flex flex-col rounded-3xl border border-tpt05-line bg-white p-8 transition-[translate,scale,filter,opacity] duration-350 ease-[cubic-bezier(.3,1.2,.3,1)] will-change-transform after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:opacity-0 after:shadow-[0_30px_60px_-22px_var(--color-tpt05-acc)] after:transition-opacity after:duration-350 after:content-[''] hover:z-10 hover:-translate-y-2.5 hover:scale-105 hover:after:opacity-60 focus-within:z-10 focus-within:-translate-y-2.5 focus-within:scale-105 focus-within:after:opacity-60 group-has-[article:hover]/g:not-hover:scale-96 group-has-[article:hover]/g:not-hover:opacity-75 group-has-[article:hover]/g:not-hover:saturate-50 motion-reduce:transition-none motion-reduce:hover:translate-y-0 motion-reduce:hover:scale-100">
        <h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt05-mut uppercase">Scale</h3>
        <p class="mt-3 text-[46px] leading-none font-extrabold tracking-[-0.035em]">$99<small class="text-[15px] font-semibold tracking-normal text-tpt05-mut"> / month</small></p>
        <ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt05-body *:flex *:gap-2.5 *:before:font-bold *:before:text-tpt05-acc *:before:content-['✓']"><li>Unlimited seats</li><li>Real-time analytics</li><li>Dedicated manager</li></ul>
        <a href="#" class="grid min-h-11 place-items-center rounded-xl bg-tpt05-ink text-sm font-bold text-white no-underline transition-colors hover:bg-tpt05-acc focus-visible:bg-tpt05-acc focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tpt05-acc">Select Scale</a>
      </article>
    </div>
    <p aria-hidden="true" class="rounded-full border border-tpt05-line bg-white/70 px-3.5 py-2 font-tpt05-mono text-[11.5px] text-tpt05-mut">group-has-[article:hover]/g:not-hover:scale-96 · hover:scale-105</p>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tpt05-bg: #f2f0f7;
  --color-tpt05-bg: oklch(0.955 0.01 300);
  --color-tpt05-glow: #e6dcfb;
  --color-tpt05-glow: oklch(0.91 0.045 300);
  --color-tpt05-ink: #1d1a26;
  --color-tpt05-ink: oklch(0.22 0.02 295);
  --color-tpt05-body: #4a4460;
  --color-tpt05-body: oklch(0.42 0.04 295);
  --color-tpt05-mut: #686280;
  --color-tpt05-mut: oklch(0.51 0.04 295);
  --color-tpt05-line: #e2dfeb;
  --color-tpt05-line: oklch(0.91 0.012 295);
  --color-tpt05-acc: #8b3fe0;
  --color-tpt05-acc: oklch(0.55 0.22 300);
  --color-tpt05-acc-ink: #6c28b8;
  --color-tpt05-acc-ink: oklch(0.47 0.21 300);
  --font-tpt05-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
  --font-tpt05-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */

.tpt-05 {
  width: 100%;
  min-height: 100svh;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<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.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-tpt05-bg: #f2f0f7;
  --color-tpt05-bg: oklch(0.955 0.01 300);
  --color-tpt05-glow: #e6dcfb;
  --color-tpt05-glow: oklch(0.91 0.045 300);
  --color-tpt05-ink: #1d1a26;
  --color-tpt05-ink: oklch(0.22 0.02 295);
  --color-tpt05-body: #4a4460;
  --color-tpt05-body: oklch(0.42 0.04 295);
  --color-tpt05-mut: #686280;
  --color-tpt05-mut: oklch(0.51 0.04 295);
  --color-tpt05-line: #e2dfeb;
  --color-tpt05-line: oklch(0.91 0.012 295);
  --color-tpt05-acc: #8b3fe0;
  --color-tpt05-acc: oklch(0.55 0.22 300);
  --color-tpt05-acc-ink: #6c28b8;
  --color-tpt05-acc-ink: oklch(0.47 0.21 300);
  --font-tpt05-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
  --font-tpt05-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */

.tpt-05 {
  width: 100%;
  min-height: 100svh;
}
3Fonts used by this demooptional — skip if you have your own type stack
<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=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • .prc-05__grid:has(.prc-05__card:hover) .prc-05__card:not(:hover) became three stacked group-has-[article:hover]/g:not-hover: utilities on each card.
  • The original's transform:translateY() scale() string became v4's independent translate and scale properties, transitioned together with transition-[translate,scale,filter,opacity].
  • UI upgrade from the CSS original: v4 gates hover: behind (hover:hover), fixing the original's sticky zoomed card after a tap on iOS.
  • UI upgrade: Growth is pre-favoured at rest (lifted, tinted border, Recommended flag) and yields when a sibling is hovered; muted copy rose from #8d87a0 (3.4:1) to 5.4:1.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
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 Hover Scale Effect
Source: https://codefronts.com/components/tailwind-css-pricing-tables/tailwind-pricing-cards-hover-scale-effect/

The classic conversion micro-interaction: hover or keyboard-focus any tier and it lifts, scales and deepens its shadow while its siblings ease back and desaturate. The sibling logic is v4's variant stacking — group-has-[article:hover]/g:not-hover:scale-96 — read left to right as &ldquo;when any card in the grid is hovered, and this one isn't&rdquo;.
## HTML
```html
<section class="tpt-05 w-full min-h-svh grid place-items-center bg-tpt05-bg bg-[radial-gradient(70%_50%_at_50%_100%,var(--color-tpt05-glow),transparent)] px-5 py-16 font-tpt05-sans text-tpt05-ink antialiased" aria-label="Pricing cards with focus hover effect">
  <div class="grid w-full max-w-5xl justify-items-center gap-11">
    <h2 class="text-center text-[clamp(26px,3.8vw,40px)] font-extrabold tracking-[-0.03em]">Pick your pace</h2>
    <div class="group/g grid w-full gap-6 md:grid-cols-3">
      <article class="relative flex flex-col rounded-3xl border border-tpt05-line bg-white p-8 transition-[translate,scale,filter,opacity] duration-350 ease-[cubic-bezier(.3,1.2,.3,1)] will-change-transform after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:opacity-0 after:shadow-[0_30px_60px_-22px_var(--color-tpt05-acc)] after:transition-opacity after:duration-350 after:content-[''] hover:z-10 hover:-translate-y-2.5 hover:scale-105 hover:after:opacity-60 focus-within:z-10 focus-within:-translate-y-2.5 focus-within:scale-105 focus-within:after:opacity-60 group-has-[article:hover]/g:not-hover:scale-96 group-has-[article:hover]/g:not-hover:opacity-75 group-has-[article:hover]/g:not-hover:saturate-50 motion-reduce:transition-none motion-reduce:hover:translate-y-0 motion-reduce:hover:scale-100">
        <h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt05-mut uppercase">Lite</h3>
        <p class="mt-3 text-[46px] leading-none font-extrabold tracking-[-0.035em]">$15<small class="text-[15px] font-semibold tracking-normal text-tpt05-mut"> / month</small></p>
        <ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt05-body *:flex *:gap-2.5 *:before:font-bold *:before:text-tpt05-acc *:before:content-['✓']"><li>2 seats</li><li>Weekly reports</li><li>Email support</li></ul>
        <a href="#" class="grid min-h-11 place-items-center rounded-xl bg-tpt05-ink text-sm font-bold text-white no-underline transition-colors hover:bg-tpt05-acc focus-visible:bg-tpt05-acc focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tpt05-acc">Select Lite</a>
      </article>
      <article class="relative flex flex-col rounded-3xl border border-tpt05-acc/40 bg-white p-8 transition-[translate,scale,filter,opacity] duration-350 ease-[cubic-bezier(.3,1.2,.3,1)] will-change-transform after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:opacity-35 after:shadow-[0_30px_60px_-22px_var(--color-tpt05-acc)] after:transition-opacity after:duration-350 after:content-[''] md:scale-[1.03] hover:z-10 hover:-translate-y-2.5 hover:scale-105 hover:after:opacity-60 focus-within:z-10 focus-within:-translate-y-2.5 focus-within:scale-105 focus-within:after:opacity-60 group-has-[article:hover]/g:not-hover:scale-96 group-has-[article:hover]/g:not-hover:opacity-75 group-has-[article:hover]/g:not-hover:saturate-50 group-has-[article:hover]/g:not-hover:after:opacity-0 motion-reduce:transition-none motion-reduce:hover:translate-y-0 motion-reduce:hover:scale-100">
        <span class="absolute -top-3 left-8 rounded-full bg-tpt05-acc px-3 py-1 text-[10.5px] font-bold tracking-[0.08em] text-white uppercase">Recommended</span>
        <h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt05-acc-ink uppercase">Growth</h3>
        <p class="mt-3 text-[46px] leading-none font-extrabold tracking-[-0.035em]">$39<small class="text-[15px] font-semibold tracking-normal text-tpt05-mut"> / month</small></p>
        <ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt05-body *:flex *:gap-2.5 *:before:font-bold *:before:text-tpt05-acc *:before:content-['✓']"><li>10 seats</li><li>Daily reports</li><li>200+ integrations</li><li>Live chat support</li></ul>
        <a href="#" class="grid min-h-11 place-items-center rounded-xl bg-tpt05-acc text-sm font-bold text-white no-underline transition-colors hover:bg-tpt05-acc-ink focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tpt05-acc">Select Growth</a>
      </article>
      <article class="relative flex flex-col rounded-3xl border border-tpt05-line bg-white p-8 transition-[translate,scale,filter,opacity] duration-350 ease-[cubic-bezier(.3,1.2,.3,1)] will-change-transform after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:opacity-0 after:shadow-[0_30px_60px_-22px_var(--color-tpt05-acc)] after:transition-opacity after:duration-350 after:content-[''] hover:z-10 hover:-translate-y-2.5 hover:scale-105 hover:after:opacity-60 focus-within:z-10 focus-within:-translate-y-2.5 focus-within:scale-105 focus-within:after:opacity-60 group-has-[article:hover]/g:not-hover:scale-96 group-has-[article:hover]/g:not-hover:opacity-75 group-has-[article:hover]/g:not-hover:saturate-50 motion-reduce:transition-none motion-reduce:hover:translate-y-0 motion-reduce:hover:scale-100">
        <h3 class="text-[13px] font-bold tracking-[0.08em] text-tpt05-mut uppercase">Scale</h3>
        <p class="mt-3 text-[46px] leading-none font-extrabold tracking-[-0.035em]">$99<small class="text-[15px] font-semibold tracking-normal text-tpt05-mut"> / month</small></p>
        <ul class="mt-6 mb-7 grid flex-1 content-start gap-2.5 text-sm text-tpt05-body *:flex *:gap-2.5 *:before:font-bold *:before:text-tpt05-acc *:before:content-['✓']"><li>Unlimited seats</li><li>Real-time analytics</li><li>Dedicated manager</li></ul>
        <a href="#" class="grid min-h-11 place-items-center rounded-xl bg-tpt05-ink text-sm font-bold text-white no-underline transition-colors hover:bg-tpt05-acc focus-visible:bg-tpt05-acc focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-tpt05-acc">Select Scale</a>
      </article>
    </div>
    <p aria-hidden="true" class="rounded-full border border-tpt05-line bg-white/70 px-3.5 py-2 font-tpt05-mono text-[11.5px] text-tpt05-mut">group-has-[article:hover]/g:not-hover:scale-96 · hover:scale-105</p>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tpt05-bg: #f2f0f7;
  --color-tpt05-bg: oklch(0.955 0.01 300);
  --color-tpt05-glow: #e6dcfb;
  --color-tpt05-glow: oklch(0.91 0.045 300);
  --color-tpt05-ink: #1d1a26;
  --color-tpt05-ink: oklch(0.22 0.02 295);
  --color-tpt05-body: #4a4460;
  --color-tpt05-body: oklch(0.42 0.04 295);
  --color-tpt05-mut: #686280;
  --color-tpt05-mut: oklch(0.51 0.04 295);
  --color-tpt05-line: #e2dfeb;
  --color-tpt05-line: oklch(0.91 0.012 295);
  --color-tpt05-acc: #8b3fe0;
  --color-tpt05-acc: oklch(0.55 0.22 300);
  --color-tpt05-acc-ink: #6c28b8;
  --color-tpt05-acc-ink: oklch(0.47 0.21 300);
  --font-tpt05-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
  --font-tpt05-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities. */

.tpt-05 {
  width: 100%;
  min-height: 100svh;
}
```

How this works

Variant stacking reads like a sentence. Each card carries its own recede rule:

group-has-[article:hover]/g:not-hover:scale-96
group-has-[article:hover]/g:not-hover:saturate-50
group-has-[article:hover]/g:not-hover:opacity-75

Hover is already safe on touch. v4's hover: compiles inside @media (hover:hover), so a tap on a phone no longer leaves a card stuck in its zoomed state.

A favourite at rest. Growth starts slightly lifted (md:scale-[1.03]) and yields when a sibling is hovered — guiding the eye without taking the choice away.

Make it yours

  • Lift strength: hover:scale-105 / hover:-translate-y-2.5.
  • How far siblings recede: the not-hover:scale-96 and saturate-50 values.
  • Remove the resting favourite by deleting md:scale-[1.03] from Growth.
  • Shadow depth: restyle the after:shadow-[…] freely — it never animates.

Gotchas — read before shipping

  • group-has-[…]: isn't a hover variant, so it isn't gated by (hover:hover); on touch it can't trigger anyway, since no card is ever hovered.
  • Keep will-change-transform on the cards only, never on the grid.
  • Scaling a card over its neighbours needs relative z-10 on the hovered one or its shadow slides underneath.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Without :has() the sibling dim is skipped and the hovered card still lifts.

Techniques used in this demo

Search CodeFronts

Loading…