Pure TailwindMIT licensed

Tailwind Bento Pricing Grid

A bento canvas instead of a tier row: the Pro tile occupies a 2×2 quadrant and free / team / stat / quote tiles fan out around it. The port swaps named grid areas for span utilities — a real trade, because col-span-2 row-span-2 lives on the tile while grid-template-areas lived in one place and drew the whole map.

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="tps-07 w-full min-h-svh bg-tps07-bg font-tps07-sans text-tps07-ink px-[clamp(20px,4vw,40px)] py-[clamp(28px,5vw,56px)]" aria-label="Pricing">
  <header class="text-center mb-[clamp(24px,4vw,36px)]">
    <h2 class="m-0 mb-2 text-[clamp(22px,3.4vw,34px)] font-bold tracking-[-0.02em] text-tps07-head text-pretty">Pricing in tiles, not tiers.</h2>
    <p class="mx-auto my-0 max-w-[480px] text-sm text-tps07-mut">One canvas, three offers, and the proof points that make the choice obvious.</p>
  </header>
  <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3.5 max-w-[980px] mx-auto">
    <article class="relative overflow-hidden flex flex-col justify-between min-h-32.5 p-5 rounded-2xl border-0 text-tps07-bg bg-linear-[135deg,var(--color-tps07-acc),var(--color-tps07-acc2)] sm:col-span-2 lg:row-span-2 before:content-[''] before:absolute before:-right-10 before:-bottom-10 before:size-40 before:rounded-full before:bg-[radial-gradient(circle,oklch(1_0_0/0.18),transparent_70%)] before:pointer-events-none">
      <div class="relative z-1 flex flex-col items-start">
        <span class="self-start mb-2 px-2.75 py-1.25 rounded-full bg-tps07-bg text-tps07-acc text-[10px] font-bold tracking-[0.1em] uppercase">Recommended</span>
        <h3 class="m-0 mb-1.5 text-[13px] font-bold tracking-[0.1em] uppercase text-tps07-bg">Pro</h3>
        <div class="mb-3 text-[clamp(36px,5vw,56px)] font-extrabold leading-none tracking-[-0.03em]"><em class="align-top pr-0.5 text-[0.5em] not-italic opacity-70">$</em>34<span class="ml-1.5 text-[0.28em] font-medium opacity-70">/mo</span></div>
        <ul class="list-none p-0 m-0 mb-4.5 text-[13px]/[1.9]">
          <li><span class="inline-block w-5 font-bold" aria-hidden="true">&#10003;</span>Unlimited projects</li>
          <li><span class="inline-block w-5 font-bold" aria-hidden="true">&#10003;</span>100 GB storage</li>
          <li><span class="inline-block w-5 font-bold" aria-hidden="true">&#10003;</span>Priority support</li>
          <li><span class="inline-block w-5 font-bold" aria-hidden="true">&#10003;</span>Custom domains</li>
        </ul>
      </div>
      <a href="#pro" class="relative z-1 self-start inline-block px-4 py-2.5 rounded-lg text-[13.5px] font-semibold no-underline bg-tps07-bg text-tps07-acc border border-tps07-bg transition-[background-color,color,border-color] duration-200 hover:bg-transparent hover:text-white hover:border-white focus-visible:outline-2 focus-visible:outline-tps07-ink focus-visible:outline-offset-3 motion-reduce:transition-none">Choose Pro &rarr;</a>
    </article>
    <article class="flex flex-col justify-between min-h-32.5 p-5 rounded-2xl bg-tps07-tile border border-tps07-edge">
      <div>
        <h3 class="m-0 mb-1.5 text-[13px] tracking-[0.1em] uppercase opacity-80">Free</h3>
        <div class="mb-3 text-[clamp(36px,5vw,56px)] font-extrabold leading-none tracking-[-0.03em]"><em class="align-top pr-0.5 text-[0.5em] not-italic opacity-70">$</em>0<span class="ml-1.5 text-[0.28em] font-medium opacity-70">forever</span></div>
        <p class="m-0 mb-3 text-[13px]/snug text-tps07-mut">Build something small, ship it, keep it free.</p>
      </div>
      <a href="#free" class="self-start inline-block px-3.5 py-2 rounded-lg text-[12.5px] font-semibold no-underline text-tps07-acc border border-tps07-ctaedge transition-[background-color,color,border-color] duration-200 hover:bg-tps07-acc hover:text-tps07-bg hover:border-tps07-acc focus-visible:outline-2 focus-visible:outline-tps07-ink focus-visible:outline-offset-3 motion-reduce:transition-none">Start free &rarr;</a>
    </article>
    <article class="flex flex-col justify-between items-start gap-2 min-h-32.5 p-5 rounded-2xl bg-tps07-tile border border-tps07-edge">
      <span class="text-[clamp(36px,5vw,50px)] font-extrabold leading-none tracking-[-0.03em] text-transparent bg-linear-to-b from-tps07-acc3 to-tps07-acc bg-clip-text forced-colors:text-[CanvasText]">14k+</span>
      <span class="text-xs/snug text-tps07-mut">teams pay for Pro every month</span>
    </article>
    <article class="flex flex-col justify-between min-h-32.5 p-5 rounded-2xl bg-tps07-tile border border-tps07-edge">
      <div>
        <h3 class="m-0 mb-1.5 text-[13px] tracking-[0.1em] uppercase opacity-80">Team</h3>
        <div class="mb-3 text-[clamp(36px,5vw,56px)] font-extrabold leading-none tracking-[-0.03em]"><em class="align-top pr-0.5 text-[0.5em] not-italic opacity-70">$</em>99<span class="ml-1.5 text-[0.28em] font-medium opacity-70">/mo</span></div>
        <p class="m-0 mb-3 text-[13px]/snug text-tps07-mut">Roles, billing, and audit logs for growing companies.</p>
      </div>
      <a href="#team" class="self-start inline-block px-3.5 py-2 rounded-lg text-[12.5px] font-semibold no-underline text-tps07-acc border border-tps07-ctaedge transition-[background-color,color,border-color] duration-200 hover:bg-tps07-acc hover:text-tps07-bg hover:border-tps07-acc focus-visible:outline-2 focus-visible:outline-tps07-ink focus-visible:outline-offset-3 motion-reduce:transition-none">Choose Team &rarr;</a>
    </article>
    <blockquote class="flex flex-col justify-between gap-2 min-h-32.5 m-0 p-5 rounded-2xl border-0 text-tps07-bg bg-linear-[135deg,var(--color-tps07-acc2),var(--color-tps07-acc4)]">
      <p class="m-0 text-[13px]/snug font-medium italic opacity-92">&ldquo;We tried five tools. This was the only one priced like a partner, not a tax.&rdquo;</p>
      <cite class="not-italic text-[11px] tracking-[0.05em] opacity-75">&mdash; Lior, CTO at Pulse</cite>
    </blockquote>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tps07-bg: #1a0d0d;
  --color-tps07-bg: oklch(0.18 0.03 30);
  --color-tps07-tile: #2a1612;
  --color-tps07-tile: oklch(0.25 0.04 32);
  --color-tps07-edge: #4a2b23;
  --color-tps07-edge: oklch(0.37 0.05 32);
  --color-tps07-ctaedge: #7a4234;
  --color-tps07-ctaedge: oklch(0.5 0.08 32);
  --color-tps07-ink: #ffe7df;
  --color-tps07-ink: oklch(0.94 0.02 30);
  --color-tps07-head: #ffd0bf;
  --color-tps07-head: oklch(0.9 0.05 40);
  --color-tps07-mut: #b89180;
  --color-tps07-mut: oklch(0.72 0.05 40);
  --color-tps07-acc: #ff6b4a;
  --color-tps07-acc: oklch(0.7 0.18 32);
  --color-tps07-acc2: #f43f5e;
  --color-tps07-acc2: oklch(0.65 0.21 15);
  --color-tps07-acc3: #ffb37a;
  --color-tps07-acc3: oklch(0.82 0.11 55);
  --color-tps07-acc4: #be123c;
  --color-tps07-acc4: oklch(0.51 0.2 15);
  --font-tps07-sans: 'Inter', system-ui, sans-serif;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh, so the section is correctly sized in the moment before the
   browser build has compiled its utilities. */

.tps-07 {
  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-tps07-bg: #1a0d0d;
  --color-tps07-bg: oklch(0.18 0.03 30);
  --color-tps07-tile: #2a1612;
  --color-tps07-tile: oklch(0.25 0.04 32);
  --color-tps07-edge: #4a2b23;
  --color-tps07-edge: oklch(0.37 0.05 32);
  --color-tps07-ctaedge: #7a4234;
  --color-tps07-ctaedge: oklch(0.5 0.08 32);
  --color-tps07-ink: #ffe7df;
  --color-tps07-ink: oklch(0.94 0.02 30);
  --color-tps07-head: #ffd0bf;
  --color-tps07-head: oklch(0.9 0.05 40);
  --color-tps07-mut: #b89180;
  --color-tps07-mut: oklch(0.72 0.05 40);
  --color-tps07-acc: #ff6b4a;
  --color-tps07-acc: oklch(0.7 0.18 32);
  --color-tps07-acc2: #f43f5e;
  --color-tps07-acc2: oklch(0.65 0.21 15);
  --color-tps07-acc3: #ffb37a;
  --color-tps07-acc3: oklch(0.82 0.11 55);
  --color-tps07-acc4: #be123c;
  --color-tps07-acc4: oklch(0.51 0.2 15);
  --font-tps07-sans: 'Inter', system-ui, sans-serif;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh, so the section is correctly sized in the moment before the
   browser build has compiled its utilities. */

.tps-07 {
  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=Inter:wght@400;500;600;700;800&display=swap">

What changed in the port

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

  • Three grid-template-areas maps (desktop, 820px, 520px) become one set of col-span/row-span utilities plus grid-cols-1 sm:grid-cols-2 lg:grid-cols-4. Fewer lines, but the mosaic is no longer visible in one place — the honest cost of the port.
  • Because spans replace areas, DOM order now equals visual order. That is an accessibility improvement (keyboard order matches the picture) and a constraint (reordering is a markup edit).
  • Five .ps-07__x { grid-area: x } rules disappear entirely; each tile's footprint is stated on the tile.
  • The Pro tile's 160px radial bloom moves from a ::after rule to before: utilities, clipped by overflow-hidden on the same element.
  • Both gradient tiles read @theme colours inside bg-linear-[135deg,…], so the palette stays centralised while the angle stays on the element.
  • self-start on pills and CTAs is doing what align-self: flex-start did in three separate rules — the same idea, stated where it applies.
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 Bento Pricing Grid
Source: https://codefronts.com/layouts/tailwind-css-pricing-sections/tailwind-bento-pricing-grid/

A bento canvas instead of a tier row: the Pro tile occupies a 2&times;2 quadrant and free / team / stat / quote tiles fan out around it. The port swaps named grid areas for span utilities &mdash; a real trade, because col-span-2 row-span-2 lives on the tile while grid-template-areas lived in one place and drew the whole map.
## HTML
```html
<section class="tps-07 w-full min-h-svh bg-tps07-bg font-tps07-sans text-tps07-ink px-[clamp(20px,4vw,40px)] py-[clamp(28px,5vw,56px)]" aria-label="Pricing">
  <header class="text-center mb-[clamp(24px,4vw,36px)]">
    <h2 class="m-0 mb-2 text-[clamp(22px,3.4vw,34px)] font-bold tracking-[-0.02em] text-tps07-head text-pretty">Pricing in tiles, not tiers.</h2>
    <p class="mx-auto my-0 max-w-[480px] text-sm text-tps07-mut">One canvas, three offers, and the proof points that make the choice obvious.</p>
  </header>
  <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3.5 max-w-[980px] mx-auto">
    <article class="relative overflow-hidden flex flex-col justify-between min-h-32.5 p-5 rounded-2xl border-0 text-tps07-bg bg-linear-[135deg,var(--color-tps07-acc),var(--color-tps07-acc2)] sm:col-span-2 lg:row-span-2 before:content-[''] before:absolute before:-right-10 before:-bottom-10 before:size-40 before:rounded-full before:bg-[radial-gradient(circle,oklch(1_0_0/0.18),transparent_70%)] before:pointer-events-none">
      <div class="relative z-1 flex flex-col items-start">
        <span class="self-start mb-2 px-2.75 py-1.25 rounded-full bg-tps07-bg text-tps07-acc text-[10px] font-bold tracking-[0.1em] uppercase">Recommended</span>
        <h3 class="m-0 mb-1.5 text-[13px] font-bold tracking-[0.1em] uppercase text-tps07-bg">Pro</h3>
        <div class="mb-3 text-[clamp(36px,5vw,56px)] font-extrabold leading-none tracking-[-0.03em]"><em class="align-top pr-0.5 text-[0.5em] not-italic opacity-70">$</em>34<span class="ml-1.5 text-[0.28em] font-medium opacity-70">/mo</span></div>
        <ul class="list-none p-0 m-0 mb-4.5 text-[13px]/[1.9]">
          <li><span class="inline-block w-5 font-bold" aria-hidden="true">&#10003;</span>Unlimited projects</li>
          <li><span class="inline-block w-5 font-bold" aria-hidden="true">&#10003;</span>100 GB storage</li>
          <li><span class="inline-block w-5 font-bold" aria-hidden="true">&#10003;</span>Priority support</li>
          <li><span class="inline-block w-5 font-bold" aria-hidden="true">&#10003;</span>Custom domains</li>
        </ul>
      </div>
      <a href="#pro" class="relative z-1 self-start inline-block px-4 py-2.5 rounded-lg text-[13.5px] font-semibold no-underline bg-tps07-bg text-tps07-acc border border-tps07-bg transition-[background-color,color,border-color] duration-200 hover:bg-transparent hover:text-white hover:border-white focus-visible:outline-2 focus-visible:outline-tps07-ink focus-visible:outline-offset-3 motion-reduce:transition-none">Choose Pro &rarr;</a>
    </article>
    <article class="flex flex-col justify-between min-h-32.5 p-5 rounded-2xl bg-tps07-tile border border-tps07-edge">
      <div>
        <h3 class="m-0 mb-1.5 text-[13px] tracking-[0.1em] uppercase opacity-80">Free</h3>
        <div class="mb-3 text-[clamp(36px,5vw,56px)] font-extrabold leading-none tracking-[-0.03em]"><em class="align-top pr-0.5 text-[0.5em] not-italic opacity-70">$</em>0<span class="ml-1.5 text-[0.28em] font-medium opacity-70">forever</span></div>
        <p class="m-0 mb-3 text-[13px]/snug text-tps07-mut">Build something small, ship it, keep it free.</p>
      </div>
      <a href="#free" class="self-start inline-block px-3.5 py-2 rounded-lg text-[12.5px] font-semibold no-underline text-tps07-acc border border-tps07-ctaedge transition-[background-color,color,border-color] duration-200 hover:bg-tps07-acc hover:text-tps07-bg hover:border-tps07-acc focus-visible:outline-2 focus-visible:outline-tps07-ink focus-visible:outline-offset-3 motion-reduce:transition-none">Start free &rarr;</a>
    </article>
    <article class="flex flex-col justify-between items-start gap-2 min-h-32.5 p-5 rounded-2xl bg-tps07-tile border border-tps07-edge">
      <span class="text-[clamp(36px,5vw,50px)] font-extrabold leading-none tracking-[-0.03em] text-transparent bg-linear-to-b from-tps07-acc3 to-tps07-acc bg-clip-text forced-colors:text-[CanvasText]">14k+</span>
      <span class="text-xs/snug text-tps07-mut">teams pay for Pro every month</span>
    </article>
    <article class="flex flex-col justify-between min-h-32.5 p-5 rounded-2xl bg-tps07-tile border border-tps07-edge">
      <div>
        <h3 class="m-0 mb-1.5 text-[13px] tracking-[0.1em] uppercase opacity-80">Team</h3>
        <div class="mb-3 text-[clamp(36px,5vw,56px)] font-extrabold leading-none tracking-[-0.03em]"><em class="align-top pr-0.5 text-[0.5em] not-italic opacity-70">$</em>99<span class="ml-1.5 text-[0.28em] font-medium opacity-70">/mo</span></div>
        <p class="m-0 mb-3 text-[13px]/snug text-tps07-mut">Roles, billing, and audit logs for growing companies.</p>
      </div>
      <a href="#team" class="self-start inline-block px-3.5 py-2 rounded-lg text-[12.5px] font-semibold no-underline text-tps07-acc border border-tps07-ctaedge transition-[background-color,color,border-color] duration-200 hover:bg-tps07-acc hover:text-tps07-bg hover:border-tps07-acc focus-visible:outline-2 focus-visible:outline-tps07-ink focus-visible:outline-offset-3 motion-reduce:transition-none">Choose Team &rarr;</a>
    </article>
    <blockquote class="flex flex-col justify-between gap-2 min-h-32.5 m-0 p-5 rounded-2xl border-0 text-tps07-bg bg-linear-[135deg,var(--color-tps07-acc2),var(--color-tps07-acc4)]">
      <p class="m-0 text-[13px]/snug font-medium italic opacity-92">&ldquo;We tried five tools. This was the only one priced like a partner, not a tax.&rdquo;</p>
      <cite class="not-italic text-[11px] tracking-[0.05em] opacity-75">&mdash; Lior, CTO at Pulse</cite>
    </blockquote>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tps07-bg: #1a0d0d;
  --color-tps07-bg: oklch(0.18 0.03 30);
  --color-tps07-tile: #2a1612;
  --color-tps07-tile: oklch(0.25 0.04 32);
  --color-tps07-edge: #4a2b23;
  --color-tps07-edge: oklch(0.37 0.05 32);
  --color-tps07-ctaedge: #7a4234;
  --color-tps07-ctaedge: oklch(0.5 0.08 32);
  --color-tps07-ink: #ffe7df;
  --color-tps07-ink: oklch(0.94 0.02 30);
  --color-tps07-head: #ffd0bf;
  --color-tps07-head: oklch(0.9 0.05 40);
  --color-tps07-mut: #b89180;
  --color-tps07-mut: oklch(0.72 0.05 40);
  --color-tps07-acc: #ff6b4a;
  --color-tps07-acc: oklch(0.7 0.18 32);
  --color-tps07-acc2: #f43f5e;
  --color-tps07-acc2: oklch(0.65 0.21 15);
  --color-tps07-acc3: #ffb37a;
  --color-tps07-acc3: oklch(0.82 0.11 55);
  --color-tps07-acc4: #be123c;
  --color-tps07-acc4: oklch(0.51 0.2 15);
  --font-tps07-sans: 'Inter', system-ui, sans-serif;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh, so the section is correctly sized in the moment before the
   browser build has compiled its utilities. */

.tps-07 {
  width: 100%;
  min-height: 100svh;
}
```

How this works

Areas become spans. The CSS version names five areas and redraws the map twice; the Tailwind version gives each tile its share of a 4-column grid:

<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3.5">
  <article class="sm:col-span-2 lg:col-span-2 lg:row-span-2 …">Pro</article>
  <article>Free</article>
  <article>14k+</article>
  <article>Team</article>
  <article>quote</article>
</div>

What you gain: each tile's footprint is readable on the tile, and the mobile and tablet layouts need no second map — source order plus grid-cols-* does it. What you lose: nobody can see the whole mosaic in one place any more. For a five-tile bento that is a fair trade; for a fifteen-cell dashboard, keep grid-template-areas in CSS and say so in a comment.

Source order is now load-bearing. With areas, DOM order and visual order were independent. With spans they are the same thing, which is better for screen readers and keyboard order — and means reordering tiles is a markup edit, not a CSS one.

The bloom is a pseudo-element, kept on the tile. before: utilities put the 160px radial glow on the Pro tile itself, with overflow-hidden clipping it to the rounded corner.

Make it yours

  • Re-proportion the mosaic by editing spans only: lg:col-span-3 on Pro and lg:col-span-1 on the rest gives a wide hero tile with a narrow rail.
  • Retheme through --color-tps07-acc (coral) and --color-tps07-acc2 (rose); the two gradient tiles, the stat numeral, every pill and every focus ring read them.
  • Tile radius and density: rounded-2xl and p-5 are the bento's rhythm — change both together or the mosaic loses its grid feel.
  • Swap the stat tile for a logo strip or a second quote — tiles are independent <article> elements with no shared state.
  • Light mode: invert the two neutral tokens and drop both gradients one lightness step; coral on cream needs darker ink than --color-tps07-bg provides.

Gotchas — read before shipping

  • Spans tie visual order to DOM order. If a tile must move visually, move it in the markup — do not reach for order-*, which desynchronises keyboard order from what users see.
  • row-span-2 only works if the row track exists. With grid-cols-1 on mobile every tile is its own row, so the span must be gated behind lg:.
  • overflow-hidden on the Pro tile is required or the before: bloom spills past the rounded corner — and it will also clip any tooltip you add later.
  • before:content-[''] is mandatory for the bloom to generate at all.
  • The gradient tiles use dark ink on coral (text-tps07-bg). Do not switch them to white text — it measures about 2.6:1 and fails WCAG 1.4.3.
  • justify-between plus self-start on the CTA is what keeps the button from stretching tile-wide; deleting either makes the bento look like a form.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Grid spans, gradients and pseudo-elements are universally supported; nothing here needs :has() or container queries. The floor quoted here is Tailwind v4's own generated sheet.

Techniques used in this demo

Theme tokensset in @theme, used by a utility

Search CodeFronts

Loading…