Pure TailwindMIT licensed

Tailwind Sale Ribbon & Coupon Badge Product Card

The clearance-page card: a diagonal ribbon wrapped across the top-right corner, a 'Best Seller' pill top-left, and a struck-through original beside the sale price. Every piece is positioning and a rotation, so the whole ribbon is absolute -right-[42px] top-[18px] w-[170px] rotate-45 and the card's overflow-hidden does the clipping.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="tpc-13 w-full min-h-svh grid place-items-center bg-tpc13-bg font-tpc13-sans px-5 py-12" aria-label="Sale ribbon product card demo">
  <article class="group relative w-[min(320px,100%)] rounded-2xl overflow-hidden bg-tpc13-card shadow-[0_16px_40px_-22px_oklch(0.25_0.03_260/0.45)]">
    <span aria-hidden="true" class="absolute top-[18px] -right-[42px] z-2 w-[170px] rotate-45 text-center py-1.75 bg-tpc13-sale text-tpc13-onacc text-[12px] font-extrabold tracking-[0.06em] shadow-[0_6px_14px_-6px_oklch(0.2_0.02_260/0.4)] transition-shadow duration-300 group-hover:shadow-[0_10px_22px_-6px_oklch(0.2_0.02_260/0.55)] motion-reduce:transition-none">SALE &minus;50%</span>
    <span class="absolute top-3.5 left-3.5 z-2 px-3 py-1.25 rounded-full bg-tpc13-ink text-tpc13-onacc text-[11px] font-bold tracking-[0.04em]">Best Seller</span>
    <div role="img" aria-label="Product photo: Halcyon bluetooth speaker" class="aspect-square bg-linear-[135deg,var(--color-tpc13-ph),var(--color-tpc13-ph2)] bg-[url('https://images.unsplash.com/photo-1589003077984-894e133dabab?w=700&h=700&fit=crop&q=70')] bg-cover bg-center"></div>
    <div class="px-5 pt-4.5 pb-5">
      <h3 class="text-[17px] font-semibold text-tpc13-ink text-pretty">Halcyon Bluetooth Speaker</h3>
      <p class="mt-2 text-[13px] text-tpc13-mut" aria-label="Rated 4.8 out of 5 from 2,140 reviews"><span aria-hidden="true" class="text-tpc13-star tracking-[0.05em]">&#9733;&#9733;&#9733;&#9733;&#9733;</span> 4.8 (2,140)</p>
      <div class="mt-3 flex items-baseline gap-2.5">
        <span class="text-[15px] text-tpc13-was line-through tabular-nums">$120</span>
        <span class="text-[24px] font-extrabold text-tpc13-sale tabular-nums">$60</span>
        <span class="sr-only">50 percent off</span>
      </div>
      <p class="mt-3 inline-flex items-center gap-2 px-3 py-1.5 rounded-lg border border-dashed border-tpc13-edge font-tpc13-mono text-[11px] font-bold tracking-[0.12em] text-tpc13-ghostink">CODE: SAVE20</p>
      <button type="button" class="mt-3.5 w-full min-h-11 h-11.5 rounded-xl border-0 cursor-pointer bg-tpc13-acc text-tpc13-onacc text-[15px] font-semibold transition-colors duration-150 hover:bg-tpc13-acc2 focus-visible:outline-3 focus-visible:outline-tpc13-ring focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
    </div>
  </article>
</section>
@import "tailwindcss";

@theme {
  --color-tpc13-bg: #f1f2f6;
  --color-tpc13-bg: oklch(0.95 0.005 265);
  --color-tpc13-card: #ffffff;
  --color-tpc13-card: oklch(1 0 0);
  --color-tpc13-ink: #111827;
  --color-tpc13-ink: oklch(0.23 0.03 265);
  --color-tpc13-mut: #5b6478;
  --color-tpc13-mut: oklch(0.5 0.025 265);
  --color-tpc13-ghostink: #3f4657;
  --color-tpc13-ghostink: oklch(0.42 0.025 265);
  --color-tpc13-was: #7d879a;
  --color-tpc13-was: oklch(0.62 0.02 265);
  --color-tpc13-edge: #c8cdd8;
  --color-tpc13-edge: oklch(0.84 0.012 265);
  --color-tpc13-ph: #e4e7ee;
  --color-tpc13-ph: oklch(0.92 0.008 265);
  --color-tpc13-ph2: #d3d8e4;
  --color-tpc13-ph2: oklch(0.87 0.014 265);
  --color-tpc13-sale: #c2341f;
  --color-tpc13-sale: oklch(0.55 0.18 28);
  --color-tpc13-acc: #3a55b0;
  --color-tpc13-acc: oklch(0.5 0.15 262);
  --color-tpc13-acc2: #2f4693;
  --color-tpc13-acc2: oklch(0.44 0.14 262);
  --color-tpc13-star: #d8a01f;
  --color-tpc13-star: oklch(0.75 0.14 82);
  --color-tpc13-ring: #a9b8e6;
  --color-tpc13-ring: oklch(0.78 0.08 262);
  --color-tpc13-onacc: #ffffff;
  --color-tpc13-onacc: oklch(1 0 0);
  --font-tpc13-sans: 'Archivo', system-ui, sans-serif;
  --font-tpc13-mono: 'JetBrains Mono', ui-monospace, monospace;
}

.tpc-13 {
  width: 100%;
  min-height: 100svh;
}

.tpc-13 ::selection {
  background: var(--color-tpc13-sale);
  color: #fff;
}

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-tpc13-bg: #f1f2f6;
  --color-tpc13-bg: oklch(0.95 0.005 265);
  --color-tpc13-card: #ffffff;
  --color-tpc13-card: oklch(1 0 0);
  --color-tpc13-ink: #111827;
  --color-tpc13-ink: oklch(0.23 0.03 265);
  --color-tpc13-mut: #5b6478;
  --color-tpc13-mut: oklch(0.5 0.025 265);
  --color-tpc13-ghostink: #3f4657;
  --color-tpc13-ghostink: oklch(0.42 0.025 265);
  --color-tpc13-was: #7d879a;
  --color-tpc13-was: oklch(0.62 0.02 265);
  --color-tpc13-edge: #c8cdd8;
  --color-tpc13-edge: oklch(0.84 0.012 265);
  --color-tpc13-ph: #e4e7ee;
  --color-tpc13-ph: oklch(0.92 0.008 265);
  --color-tpc13-ph2: #d3d8e4;
  --color-tpc13-ph2: oklch(0.87 0.014 265);
  --color-tpc13-sale: #c2341f;
  --color-tpc13-sale: oklch(0.55 0.18 28);
  --color-tpc13-acc: #3a55b0;
  --color-tpc13-acc: oklch(0.5 0.15 262);
  --color-tpc13-acc2: #2f4693;
  --color-tpc13-acc2: oklch(0.44 0.14 262);
  --color-tpc13-star: #d8a01f;
  --color-tpc13-star: oklch(0.75 0.14 82);
  --color-tpc13-ring: #a9b8e6;
  --color-tpc13-ring: oklch(0.78 0.08 262);
  --color-tpc13-onacc: #ffffff;
  --color-tpc13-onacc: oklch(1 0 0);
  --font-tpc13-sans: 'Archivo', system-ui, sans-serif;
  --font-tpc13-mono: 'JetBrains Mono', ui-monospace, monospace;
}

.tpc-13 {
  width: 100%;
  min-height: 100svh;
}

.tpc-13 ::selection {
  background: var(--color-tpc13-sale);
  color: #fff;
}
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=Archivo:wght@400;500;600;700;800&family=JetBrains+Mono:wght@500;700&display=swap">

What changed in the port

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

  • The whole ribbon rule — position, offsets, width, rotation, centring — becomes one class list on the band itself. This is the port where reading the markup tells you more than reading the CSS did: the two numbers that control ribbon length sit side by side.
  • z-2 is v4's arbitrary-free z-index scale; the CSS original's z-index:2 needed no translation.
  • The fake ribbon 'fold' pseudo-elements from the original were dropped rather than ported. They were two more rules for an effect the flat band already reads as, and ::before/::after content is exactly where utility markup stops being clearer.
  • Enhancement over the CSS original: the dashed coupon chip the original listed as a customisation is shipped, the discount gained an sr-only percentage so AT users get the saving as text, and the ribbon's shadow now deepens with group-hover: instead of sitting inert.
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 Sale Ribbon &amp; Coupon Badge Product Card
Source: https://codefronts.com/components/tailwind-css-product-cards/tailwind-sale-ribbon-coupon-badge-product-card/

The clearance-page card: a diagonal ribbon wrapped across the top-right corner, a 'Best Seller' pill top-left, and a struck-through original beside the sale price. Every piece is positioning and a rotation, so the whole ribbon is absolute -right-[42px] top-[18px] w-[170px] rotate-45 and the card's overflow-hidden does the clipping.
## HTML
```html
<section class="tpc-13 w-full min-h-svh grid place-items-center bg-tpc13-bg font-tpc13-sans px-5 py-12" aria-label="Sale ribbon product card demo">
  <article class="group relative w-[min(320px,100%)] rounded-2xl overflow-hidden bg-tpc13-card shadow-[0_16px_40px_-22px_oklch(0.25_0.03_260/0.45)]">
    <span aria-hidden="true" class="absolute top-[18px] -right-[42px] z-2 w-[170px] rotate-45 text-center py-1.75 bg-tpc13-sale text-tpc13-onacc text-[12px] font-extrabold tracking-[0.06em] shadow-[0_6px_14px_-6px_oklch(0.2_0.02_260/0.4)] transition-shadow duration-300 group-hover:shadow-[0_10px_22px_-6px_oklch(0.2_0.02_260/0.55)] motion-reduce:transition-none">SALE &minus;50%</span>
    <span class="absolute top-3.5 left-3.5 z-2 px-3 py-1.25 rounded-full bg-tpc13-ink text-tpc13-onacc text-[11px] font-bold tracking-[0.04em]">Best Seller</span>
    <div role="img" aria-label="Product photo: Halcyon bluetooth speaker" class="aspect-square bg-linear-[135deg,var(--color-tpc13-ph),var(--color-tpc13-ph2)] bg-[url('https://images.unsplash.com/photo-1589003077984-894e133dabab?w=700&h=700&fit=crop&q=70')] bg-cover bg-center"></div>
    <div class="px-5 pt-4.5 pb-5">
      <h3 class="text-[17px] font-semibold text-tpc13-ink text-pretty">Halcyon Bluetooth Speaker</h3>
      <p class="mt-2 text-[13px] text-tpc13-mut" aria-label="Rated 4.8 out of 5 from 2,140 reviews"><span aria-hidden="true" class="text-tpc13-star tracking-[0.05em]">&#9733;&#9733;&#9733;&#9733;&#9733;</span> 4.8 (2,140)</p>
      <div class="mt-3 flex items-baseline gap-2.5">
        <span class="text-[15px] text-tpc13-was line-through tabular-nums">$120</span>
        <span class="text-[24px] font-extrabold text-tpc13-sale tabular-nums">$60</span>
        <span class="sr-only">50 percent off</span>
      </div>
      <p class="mt-3 inline-flex items-center gap-2 px-3 py-1.5 rounded-lg border border-dashed border-tpc13-edge font-tpc13-mono text-[11px] font-bold tracking-[0.12em] text-tpc13-ghostink">CODE: SAVE20</p>
      <button type="button" class="mt-3.5 w-full min-h-11 h-11.5 rounded-xl border-0 cursor-pointer bg-tpc13-acc text-tpc13-onacc text-[15px] font-semibold transition-colors duration-150 hover:bg-tpc13-acc2 focus-visible:outline-3 focus-visible:outline-tpc13-ring focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
    </div>
  </article>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tpc13-bg: #f1f2f6;
  --color-tpc13-bg: oklch(0.95 0.005 265);
  --color-tpc13-card: #ffffff;
  --color-tpc13-card: oklch(1 0 0);
  --color-tpc13-ink: #111827;
  --color-tpc13-ink: oklch(0.23 0.03 265);
  --color-tpc13-mut: #5b6478;
  --color-tpc13-mut: oklch(0.5 0.025 265);
  --color-tpc13-ghostink: #3f4657;
  --color-tpc13-ghostink: oklch(0.42 0.025 265);
  --color-tpc13-was: #7d879a;
  --color-tpc13-was: oklch(0.62 0.02 265);
  --color-tpc13-edge: #c8cdd8;
  --color-tpc13-edge: oklch(0.84 0.012 265);
  --color-tpc13-ph: #e4e7ee;
  --color-tpc13-ph: oklch(0.92 0.008 265);
  --color-tpc13-ph2: #d3d8e4;
  --color-tpc13-ph2: oklch(0.87 0.014 265);
  --color-tpc13-sale: #c2341f;
  --color-tpc13-sale: oklch(0.55 0.18 28);
  --color-tpc13-acc: #3a55b0;
  --color-tpc13-acc: oklch(0.5 0.15 262);
  --color-tpc13-acc2: #2f4693;
  --color-tpc13-acc2: oklch(0.44 0.14 262);
  --color-tpc13-star: #d8a01f;
  --color-tpc13-star: oklch(0.75 0.14 82);
  --color-tpc13-ring: #a9b8e6;
  --color-tpc13-ring: oklch(0.78 0.08 262);
  --color-tpc13-onacc: #ffffff;
  --color-tpc13-onacc: oklch(1 0 0);
  --font-tpc13-sans: 'Archivo', system-ui, sans-serif;
  --font-tpc13-mono: 'JetBrains Mono', ui-monospace, monospace;
}

.tpc-13 {
  width: 100%;
  min-height: 100svh;
}

.tpc-13 ::selection {
  background: var(--color-tpc13-sale);
  color: #fff;
}
```

How this works

A ribbon is a rotated box plus a clip.

<article class="relative overflow-hidden rounded-2xl">
  <span class="absolute top-[18px] -right-[42px] z-2 w-[170px] rotate-45 text-center">SALE −50%</span>

The band is wider than the corner it crosses and hangs off the right edge; the card's overflow-hidden trims both ends flush. Change the width or the offset and the ribbon's apparent length changes — they are the two numbers to tune, and here they sit inches from each other in the same class list.

The badge system is one recipe. Pill, ribbon and coupon chip all share rounded-full (or rounded-lg), a tight uppercase tracking and an 11px size, so three different promo mechanics read as one family.

The discount is text, not decoration. The ribbon is aria-hidden flavour; the actual saving lives in the price line, where a screen reader finds it: an original with line-through, the sale price, and a labelled percentage.

Make it yours

  • Ribbon colour: --color-tpc13-sale. Red reads clearance, green reads new, black reads premium drop.
  • Mirror it to the top-left with -left-[42px] -rotate-45.
  • Flat tag instead: drop the rotate-45 and use left-0 top-4 rounded-r-full.
  • Coupon chip: swap the code text, or delete the chip entirely — nothing else depends on it.
  • Keep ribbon copy under about 12 characters; w-[170px] is the budget.

Gotchas — read before shipping

  • Without overflow-hidden on the card the rotated band sticks out past the corner and breaks the grid it sits in.
  • overflow-hidden also clips any hover lift shadow drawn inside the card — put the shadow on the card itself, as here.
  • Badges must not be the only carrier of the discount. The struck price and the percentage text are what AT users get.
  • Rotated text in a narrow band is the first thing to break at 200% zoom — test the ribbon copy at large text sizes.
  • z-2 matters: the ribbon has to sit above the media layer, not under it.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

A rotated absolute band clipped by overflow is universally supported; the floor quoted is Tailwind v4's own generated sheet.

Techniques used in this demo

Theme tokensset in @theme, used by a utility

Search CodeFronts

Loading…