Pricing table

프라이싱 테이블

A row of plan cards with one highlighted to steer the choice, plus a monthly/yearly toggle.

Also known as: Pricing plansPlan comparison cards
···
html
<div class="pricing">
  <div class="toggle" id="toggle"><span class="lbl">Monthly</span><span class="switch"><i id="knob"></i></span><span class="lbl">Yearly</span></div>
  <div class="cards">
    <div class="plan"><h4>Starter</h4><div class="price"><span id="p1">$9</span><small>/mo</small></div><span class="cta">Choose</span></div>
    <div class="plan pop"><span class="badge">Popular</span><h4>Pro</h4><div class="price"><span id="p2">$29</span><small>/mo</small></div><span class="cta">Choose</span></div>
    <div class="plan"><h4>Scale</h4><div class="price"><span id="p3">$79</span><small>/mo</small></div><span class="cta">Choose</span></div>
  </div>
</div>
css
.pricing{width:min(94%,760px);display:flex;flex-direction:column;align-items:center;gap:clamp(8px,2vmin,16px)}
.toggle{display:flex;align-items:center;gap:8px;font-size:clamp(8px,1.5vmin,12px);color:var(--muted)}
.switch{width:clamp(24px,5vmin,36px);height:clamp(13px,2.8vmin,20px);border-radius:999px;background:var(--line);
  position:relative;flex:none}
.switch i{position:absolute;top:10%;left:6%;width:44%;aspect-ratio:1;border-radius:50%;background:var(--accent);
  transition:transform .4s cubic-bezier(.2,.8,.2,1)}
.switch.on i{transform:translateX(90%)}
.cards{display:flex;gap:clamp(6px,1.5vmin,12px);width:100%}
.plan{flex:1;background:var(--surface);border:1px solid var(--line);border-radius:10px;
  padding:clamp(8px,2vmin,16px);display:flex;flex-direction:column;align-items:flex-start;gap:6%;position:relative}
.plan.pop{border-color:var(--accent);box-shadow:0 8px 20px color-mix(in oklab,var(--accent) 30%,transparent);
  transform:translateY(-3%)}
.badge{position:absolute;top:-9px;right:8%;font-size:clamp(6px,1.1vmin,9px);font-weight:700;color:#fff;
  background:var(--accent);padding:.2em .7em;border-radius:999px}
.plan h4{margin:0;font-size:clamp(8px,1.6vmin,12px);color:var(--muted);font-weight:600}
.price{font-size:clamp(13px,3.4vmin,24px);font-weight:800}
.price small{font-size:.4em;color:var(--muted);font-weight:500}
.cta{margin-top:auto;align-self:stretch;text-align:center;font-size:clamp(7px,1.4vmin,11px);font-weight:700;
  padding:.5em 0;border-radius:6px;background:var(--line);color:var(--fg)}
.plan.pop .cta{background:var(--accent);color:#fff}
js
const monthly = { p1: '$9', p2: '$29', p3: '$79' };
const yearly = { p1: '$7', p2: '$23', p3: '$63' };
const knob = document.getElementById('knob');
let isYearly = false;
function render() {
  const prices = isYearly ? yearly : monthly;
  Object.keys(prices).forEach(function (id) {
    document.getElementById(id).textContent = prices[id];
  });
  knob.parentElement.classList.toggle('on', isYearly);
}
render();
setInterval(function () {
  isYearly = !isYearly;
  render();
}, 2400);

Usually two to four cards side by side, with one — typically the middle tier — highlighted slightly larger, in a different color, with a "Most popular" badge. That highlight acts as a nudge: people gravitate to the middle instead of the cheapest or priciest extreme.

A monthly/yearly toggle must recompute every card's price the instant it flips, and yearly should show the discount explicitly ("2 months free") to make the switch feel worth it. Each card pairs a price, a one-line "who this is for," a checklist of included features, and a CTA button.

If the feature checklist is ordered differently per card, comparison gets hard — keep the same feature on the same row across every card. If that's not possible, switch to a `comparison-table` instead.

When to use

Good when there are only two to four simple tiers. If there are many features to compare line by line, `comparison-table` communicates it more clearly.