21 CSS Pricing Sections17 / 21

Pure CSSMIT licensed

Currency Switcher

A pure-CSS currency switcher (USD / EUR / GBP) using hidden radios + :has() to swap every visible price across all three tiers. Burgundy on cream — the wine-merchant / boutique-software aesthetic.

Published

Live Demo
Try it

The code

<section class="ps-17" aria-label="Pricing">
  <header class="ps-17__head">
    <h2>Pricing in your currency.</h2>
    <p>Pay where you live, with the rate fixed at billing time.</p>
    <fieldset class="ps-17__tabs">
      <legend class="ps-17__sr">Currency</legend>
      <input type="radio" name="ps-17__c" id="ps-17__usd" checked />
      <label for="ps-17__usd">USD</label>
      <input type="radio" name="ps-17__c" id="ps-17__eur" />
      <label for="ps-17__eur">EUR</label>
      <input type="radio" name="ps-17__c" id="ps-17__gbp" />
      <label for="ps-17__gbp">GBP</label>
    </fieldset>
  </header>
  <div class="ps-17__grid">
    <article class="ps-17__card">
      <h3>Petit</h3>
      <div class="ps-17__price">
        <span class="ps-17__usd">$12</span><span class="ps-17__eur">€11</span
        ><span class="ps-17__gbp">£10</span>
        <em>/month</em>
      </div>
      <ul>
        <li>Solo cellar</li>
        <li>3 bottles tracked</li>
        <li>Email reminders</li>
      </ul>
      <a class="ps-17__cta" href="#petit">Choose Petit</a>
    </article>
    <article class="ps-17__card ps-17__best">
      <span class="ps-17__pill">Sommelier’s pick</span>
      <h3>Reserve</h3>
      <div class="ps-17__price">
        <span class="ps-17__usd">$36</span><span class="ps-17__eur">€33</span
        ><span class="ps-17__gbp">£28</span>
        <em>/month</em>
      </div>
      <ul>
        <li>Full cellar</li>
        <li>Unlimited bottles</li>
        <li>Tasting notes</li>
        <li>Pairing engine</li>
      </ul>
      <a class="ps-17__cta ps-17__cta-pri" href="#reserve">Choose Reserve</a>
    </article>
    <article class="ps-17__card">
      <h3>Grand Cru</h3>
      <div class="ps-17__price">
        <span class="ps-17__usd">$96</span><span class="ps-17__eur">€88</span
        ><span class="ps-17__gbp">£76</span>
        <em>/month</em>
      </div>
      <ul>
        <li>Multi-cellar</li>
        <li>Insurance valuation</li>
        <li>White-glove setup</li>
      </ul>
      <a class="ps-17__cta" href="#grand">Talk to us</a>
    </article>
  </div>
</section>
.ps-17 {
  padding: clamp(28px, 5vw, 56px) clamp(20px, 4vw, 40px);
  width: 100%;
  min-height: 100vh;
  background: #faf6ee;
  color: #2a0a14;
  font-family: 'Inter', system-ui, sans-serif;
}

.ps-17__head {
  text-align: center;
  margin-bottom: clamp(24px, 4vw, 36px);
}

.ps-17__head h2 {
  font-family: 'Playfair Display', Georgia, serif;
  font-size: clamp(26px, 4vw, 38px);
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0 0 8px;
  color: #6b1224;
}

.ps-17__head p {
  color: #8a4555;
  margin: 0 0 20px;
  font-size: 14px;
}

.ps-17__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  border: 0;
}

.ps-17__tabs {
  position: relative;
  display: inline-grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  border: 1.5px solid #6b1224;
  border-radius: 999px;
  padding: 3px;
  background: #fff;
  margin: 0;
}

.ps-17__tabs input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.ps-17__tabs label {
  padding: 7px 22px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: #8a4555;
  cursor: pointer;
  border-radius: 999px;
  transition: color 0.18s, background 0.18s;
}

.ps-17__tabs input:checked + label {
  background: #6b1224;
  color: #faf6ee;
}

.ps-17__tabs input:focus-visible + label {
  outline: 2px solid #6b1224;
  outline-offset: 3px;
}

.ps-17__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  max-width: 1000px;
  margin: 0 auto;
  align-items: center;
}

.ps-17__card {
  position: relative;
  background: #fff;
  border: 1px solid #e7d8c8;
  border-radius: 8px;
  padding: 26px 22px 22px;
  display: flex;
  flex-direction: column;
}

.ps-17__best {
  background: #6b1224;
  color: #faf6ee;
  border: 0;
  transform: scale(1.04);
  box-shadow: 0 18px 44px rgba(107,18,36,0.3);
}

.ps-17__pill {
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  background: #faf6ee;
  color: #6b1224;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 4px 11px;
  border: 1.5px solid #6b1224;
  border-radius: 999px;
}

.ps-17__card h3 {
  font-family: 'Playfair Display', Georgia, serif;
  font-size: 22px;
  font-weight: 700;
  margin: 0 0 12px;
  color: #6b1224;
  font-style: italic;
}

.ps-17__best h3 {
  color: #faf6ee;
}

.ps-17__price {
  display: flex;
  align-items: baseline;
  gap: 4px;
  margin-bottom: 18px;
  padding-bottom: 18px;
  border-bottom: 1px dashed #e7d8c8;
  font-size: 38px;
  font-weight: 800;
  letter-spacing: -0.03em;
}

.ps-17__best .ps-17__price {
  border-bottom-color: rgba(250,246,238,0.25);
}

.ps-17__price em {
  font-size: 13px;
  font-weight: 500;
  color: #8a4555;
  font-style: normal;
  margin-left: 6px;
}

.ps-17__best .ps-17__price em {
  color: rgba(250,246,238,0.7);
}

.ps-17__price > span {
  display: none;
}

.ps-17:has(#ps-17__usd:checked) .ps-17__usd,
.ps-17:has(#ps-17__eur:checked) .ps-17__eur,
.ps-17:has(#ps-17__gbp:checked) .ps-17__gbp {
  display: inline;
}

.ps-17__card ul {
  list-style: none;
  padding: 0;
  margin: 0 0 20px;
  flex: 1;
  font-size: 13.5px;
  line-height: 1.95;
  color: #4a2030;
}

.ps-17__best ul {
  color: rgba(250,246,238,0.85);
}

.ps-17__card ul li::before {
  content: '◆';
  color: #6b1224;
  display: inline-block;
  width: 20px;
  font-size: 9px;
}

.ps-17__best ul li::before {
  color: #faf6ee;
}

.ps-17__cta {
  display: block;
  text-align: center;
  padding: 11px 16px;
  border-radius: 6px;
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1.5px solid currentColor;
  color: #6b1224;
  background: transparent;
  transition: background 0.18s, color 0.18s;
}

.ps-17__best .ps-17__cta {
  color: #faf6ee;
}

.ps-17__cta-pri {
  background: #faf6ee;
  color: #6b1224 !important;
  border-color: #faf6ee;
}

.ps-17__cta:hover {
  background: #6b1224;
  color: #faf6ee;
  border-color: #6b1224;
}

.ps-17__cta-pri:hover {
  background: transparent;
  color: #faf6ee !important;
  border-color: #faf6ee;
}

.ps-17__cta:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

@media (max-width: 820px) {
  .ps-17__grid {
    grid-template-columns: 1fr;
    max-width: 380px;
  }

  .ps-17__best {
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ps-17__tabs label,
    .ps-17__cta {
    transition: none;
  }
}
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 Pricing Section 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: Currency Switcher
Source: https://codefronts.com/layouts/css-pricing-sections/currency-switcher/

A pure-CSS currency switcher (USD / EUR / GBP) using hidden radios + :has() to swap every visible price across all three tiers. Burgundy on cream — the wine-merchant / boutique-software aesthetic.
## HTML
```html
<section class="ps-17" aria-label="Pricing">
  <header class="ps-17__head">
    <h2>Pricing in your currency.</h2>
    <p>Pay where you live, with the rate fixed at billing time.</p>
    <fieldset class="ps-17__tabs">
      <legend class="ps-17__sr">Currency</legend>
      <input type="radio" name="ps-17__c" id="ps-17__usd" checked />
      <label for="ps-17__usd">USD</label>
      <input type="radio" name="ps-17__c" id="ps-17__eur" />
      <label for="ps-17__eur">EUR</label>
      <input type="radio" name="ps-17__c" id="ps-17__gbp" />
      <label for="ps-17__gbp">GBP</label>
    </fieldset>
  </header>
  <div class="ps-17__grid">
    <article class="ps-17__card">
      <h3>Petit</h3>
      <div class="ps-17__price">
        <span class="ps-17__usd">$12</span><span class="ps-17__eur">€11</span
        ><span class="ps-17__gbp">£10</span>
        <em>/month</em>
      </div>
      <ul>
        <li>Solo cellar</li>
        <li>3 bottles tracked</li>
        <li>Email reminders</li>
      </ul>
      <a class="ps-17__cta" href="#petit">Choose Petit</a>
    </article>
    <article class="ps-17__card ps-17__best">
      <span class="ps-17__pill">Sommelier’s pick</span>
      <h3>Reserve</h3>
      <div class="ps-17__price">
        <span class="ps-17__usd">$36</span><span class="ps-17__eur">€33</span
        ><span class="ps-17__gbp">£28</span>
        <em>/month</em>
      </div>
      <ul>
        <li>Full cellar</li>
        <li>Unlimited bottles</li>
        <li>Tasting notes</li>
        <li>Pairing engine</li>
      </ul>
      <a class="ps-17__cta ps-17__cta-pri" href="#reserve">Choose Reserve</a>
    </article>
    <article class="ps-17__card">
      <h3>Grand Cru</h3>
      <div class="ps-17__price">
        <span class="ps-17__usd">$96</span><span class="ps-17__eur">€88</span
        ><span class="ps-17__gbp">£76</span>
        <em>/month</em>
      </div>
      <ul>
        <li>Multi-cellar</li>
        <li>Insurance valuation</li>
        <li>White-glove setup</li>
      </ul>
      <a class="ps-17__cta" href="#grand">Talk to us</a>
    </article>
  </div>
</section>
```
## CSS
```css
.ps-17 {
  padding: clamp(28px, 5vw, 56px) clamp(20px, 4vw, 40px);
  width: 100%;
  min-height: 100vh;
  background: #faf6ee;
  color: #2a0a14;
  font-family: 'Inter', system-ui, sans-serif;
}

.ps-17__head {
  text-align: center;
  margin-bottom: clamp(24px, 4vw, 36px);
}

.ps-17__head h2 {
  font-family: 'Playfair Display', Georgia, serif;
  font-size: clamp(26px, 4vw, 38px);
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0 0 8px;
  color: #6b1224;
}

.ps-17__head p {
  color: #8a4555;
  margin: 0 0 20px;
  font-size: 14px;
}

.ps-17__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  border: 0;
}

.ps-17__tabs {
  position: relative;
  display: inline-grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  border: 1.5px solid #6b1224;
  border-radius: 999px;
  padding: 3px;
  background: #fff;
  margin: 0;
}

.ps-17__tabs input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.ps-17__tabs label {
  padding: 7px 22px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: #8a4555;
  cursor: pointer;
  border-radius: 999px;
  transition: color 0.18s, background 0.18s;
}

.ps-17__tabs input:checked + label {
  background: #6b1224;
  color: #faf6ee;
}

.ps-17__tabs input:focus-visible + label {
  outline: 2px solid #6b1224;
  outline-offset: 3px;
}

.ps-17__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  max-width: 1000px;
  margin: 0 auto;
  align-items: center;
}

.ps-17__card {
  position: relative;
  background: #fff;
  border: 1px solid #e7d8c8;
  border-radius: 8px;
  padding: 26px 22px 22px;
  display: flex;
  flex-direction: column;
}

.ps-17__best {
  background: #6b1224;
  color: #faf6ee;
  border: 0;
  transform: scale(1.04);
  box-shadow: 0 18px 44px rgba(107,18,36,0.3);
}

.ps-17__pill {
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  background: #faf6ee;
  color: #6b1224;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 4px 11px;
  border: 1.5px solid #6b1224;
  border-radius: 999px;
}

.ps-17__card h3 {
  font-family: 'Playfair Display', Georgia, serif;
  font-size: 22px;
  font-weight: 700;
  margin: 0 0 12px;
  color: #6b1224;
  font-style: italic;
}

.ps-17__best h3 {
  color: #faf6ee;
}

.ps-17__price {
  display: flex;
  align-items: baseline;
  gap: 4px;
  margin-bottom: 18px;
  padding-bottom: 18px;
  border-bottom: 1px dashed #e7d8c8;
  font-size: 38px;
  font-weight: 800;
  letter-spacing: -0.03em;
}

.ps-17__best .ps-17__price {
  border-bottom-color: rgba(250,246,238,0.25);
}

.ps-17__price em {
  font-size: 13px;
  font-weight: 500;
  color: #8a4555;
  font-style: normal;
  margin-left: 6px;
}

.ps-17__best .ps-17__price em {
  color: rgba(250,246,238,0.7);
}

.ps-17__price > span {
  display: none;
}

.ps-17:has(#ps-17__usd:checked) .ps-17__usd,
.ps-17:has(#ps-17__eur:checked) .ps-17__eur,
.ps-17:has(#ps-17__gbp:checked) .ps-17__gbp {
  display: inline;
}

.ps-17__card ul {
  list-style: none;
  padding: 0;
  margin: 0 0 20px;
  flex: 1;
  font-size: 13.5px;
  line-height: 1.95;
  color: #4a2030;
}

.ps-17__best ul {
  color: rgba(250,246,238,0.85);
}

.ps-17__card ul li::before {
  content: '◆';
  color: #6b1224;
  display: inline-block;
  width: 20px;
  font-size: 9px;
}

.ps-17__best ul li::before {
  color: #faf6ee;
}

.ps-17__cta {
  display: block;
  text-align: center;
  padding: 11px 16px;
  border-radius: 6px;
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1.5px solid currentColor;
  color: #6b1224;
  background: transparent;
  transition: background 0.18s, color 0.18s;
}

.ps-17__best .ps-17__cta {
  color: #faf6ee;
}

.ps-17__cta-pri {
  background: #faf6ee;
  color: #6b1224 !important;
  border-color: #faf6ee;
}

.ps-17__cta:hover {
  background: #6b1224;
  color: #faf6ee;
  border-color: #6b1224;
}

.ps-17__cta-pri:hover {
  background: transparent;
  color: #faf6ee !important;
  border-color: #faf6ee;
}

.ps-17__cta:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

@media (max-width: 820px) {
  .ps-17__grid {
    grid-template-columns: 1fr;
    max-width: 380px;
  }

  .ps-17__best {
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ps-17__tabs label,
    .ps-17__cta {
    transition: none;
  }
}
```

How this works

The whole saas pricing page is a single semantic <section> with a header (h2 + fieldset of three radios) and a display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) tier row. The currency switcher pricing pattern is pure CSS: three hidden <input type="radio" name="ps-17__c"> siblings live inside .ps-17__tabs, and the container uses :has() to reveal the matching price spans — .ps-17:has(#ps-17__usd:checked) .ps-17__usd { display: inline } swaps every visible price across all three tiers without a byte of JavaScript. The recommended card gets transform: scale(1.04) plus a 0 18px 44px rgba(107,18,36,0.3) burgundy glow — visual anchoring for the Sommelier's pick tier.

The palette leans wine-merchant: cream #faf6ee base, deep burgundy #6b1224 as the primary, muted rose #8a4555 for supporting copy, and warm bone #e7d8c8 for the dashed price divider. Playfair Display serif italics on the tier names read as boutique-software; JetBrains Mono at letter-spacing: 0.1em on the currency labels signals engineered precision — the exact split editorial fintech and premium B2B SaaS use to look expensive without shouting. Prices sit at font-size: 38px; font-weight: 800; letter-spacing: -0.03em so the digits carry weight even at the 340px mobile breakpoint.

Why it converts: Baymard cross-border checkout research shows that displaying prices in the shopper's home currency cuts friction on international purchases by 30-50%, and shopper trust roughly doubles versus USD-only pricing. The pill-style tab group sits directly under the h2 where scanning eyes land first, so the multi-currency pricing decision happens before the tier decision. The dashed 1px dashed #e7d8c8 divider between price and feature list creates a Baymard-validated scan break that lifts feature-read rate on global SaaS pricing pages.

Make it yours

  • Recolor to your brand by editing four values: the cream background (#faf6ee), the burgundy primary (#6b1224), the muted rose support text (#8a4555), and the bone divider (#e7d8c8). Fintech tends to prefer navy #0b1e3f primary; dev-tools SaaS swap to charcoal #1a1a1a with lime accent.
  • Add JPY, CAD, or AUD by duplicating the radio + label pair inside .ps-17__tabs, adding a matching .ps-17__jpy span inside each .ps-17__price, and appending .ps-17:has(#ps-17__jpy:checked) .ps-17__jpy { display: inline }. The :has() pattern scales to any number of currencies with zero JS.
  • Swap the serif italic Playfair Display for 'Fraunces' for a warmer editorial feel, 'DM Serif Display' for boutique-SaaS, or 'Inter' at font-weight: 700 if you want a modern-fintech look. Keep JetBrains Mono on the currency tabs — the mono/serif contrast is what makes the picker read as intentional.
  • Change the CTA shape: border-radius: 6px reads as classic-boutique. Bump to border-radius: 999px for pill-style modern SaaS, or drop to border-radius: 0 for editorial. The outlined border: 1.5px solid currentColor pattern makes recoloring trivial — swap color and the border follows.
  • For Tailwind: use bg-[#faf6ee] font-sans on the section, font-serif italic text-[#6b1224] on tier names, bg-[#6b1224] text-[#faf6ee] on the recommended card. The :has() currency swap needs arbitrary variants: [&:has(#ps-17__eur:checked)_.ps-17__eur]:inline. React/Next parity: track currency in state and toggle a data attribute if :has() support is a concern (Firefox <121 lacks it).

Gotchas — read before shipping

  • The :has() selector is not supported in Firefox before 121 (Dec 2023) and Chrome/Safari before 105/15.4. If your fintech or B2B SaaS analytics show >1% traffic on older browsers, ship a JS fallback that toggles a class on .ps-17 based on radio change, and rewrite the selectors as .ps-17.is-usd .ps-17__usd { display: inline }.
  • The transform: scale(1.04) on .ps-17__best creates a new stacking context — child z-index values now stack against this card, not the page. If you later add an absolutely-positioned tooltip that must overlap the neighbouring tier, either raise its z-index above the sibling card or drop scale in favour of padding. It also nudges the card ~2px past its column edge on narrow desktops — the mobile media query resets this via transform: none.
  • The burgundy primary #6b1224 on cream #faf6ee hits ~11.5:1 contrast — passes WCAG AAA (1.4.3). But the muted rose #8a4555 support copy on cream reads at ~5.1:1, AA only for large text (14px+). The .ps-17__head p support paragraph is 14px so it just clears; if you shrink it, either bump the color to #701f30 or scale to 16px.
  • The hidden <input type="radio"> uses opacity: 0; pointer-events: none — visually hidden but keyboard-reachable via the label's for attribute. The :focus-visible + label outline is what makes WCAG 2.4.7 (Focus Visible) pass. Never remove the outline. Also keep the legend.ps-17__sr screen-reader label — screen-reader users need to know the fieldset is a currency picker, not just three buttons.
  • Playfair Display italics look great when the font file actually ships italics; the Google Fonts default variant does. If you self-host and forget the italic subset, browsers synthesize a slanted roman that looks janky on tier names. Verify your @font-face block includes font-style: italic, or the boutique-software vibe collapses.
  • The .ps-17__price > span { display: none } + :has() reveal pattern means every currency span still sits in the DOM — screen readers may read all three prices in a row on page load before JS or CSS class-based hiding kicks in. If your international SaaS audience relies on assistive tech, add aria-hidden="true" to non-active currency spans via a tiny script; a pure-CSS content-visibility: hidden won't help because :has() can't toggle attributes.

Techniques used in this demo

Search CodeFronts

Loading…