Book a callGitHub5

Order summary

Oskarby Analytics
  • Extra seats$48.00 per seat a month $96.00
    2
  • Usage credit, $250 packUsed before card charges; never expires $500.00
    2
Promo code
AUTUMN15 · 15% off
Subtotal
$596.00
Discount, 15%
−$89.40
Sales tax, 8.25%
$41.79
Due today
$548.39USD

Charged to the card ending 2861. Seats renew on Nov 1.

It is live: hover, focus and its own controls respond. Actions that would change data (approve, send, delete) are for your app to wire. The width is a real 390 px, 768 px or 1280 px box, shrunk to fit your screen.

Source
<style>
.odl-order-summary { box-sizing: border-box; inline-size: 100%; max-inline-size: 440px; container-type: inline-size; text-wrap: pretty; }
.odl-order-summary *, .odl-order-summary *::before { box-sizing: border-box; }
.odl-order-summary .odl-card { display: grid; gap: var(--ds-space-stack-lg); padding: var(--ds-space-inset-lg); background: var(--ds-color-surface-raised); color: var(--ds-color-text-primary);
  border: var(--ds-border-width-default) solid var(--ds-color-border-subtle); border-radius: var(--ds-radius-container); box-shadow: var(--ds-elevation-raised); font: var(--ds-text-body-md); }
.odl-order-summary .odl-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--ds-space-inline-sm); }
.odl-order-summary h3 { margin: 0; font: var(--ds-text-title-sm); }
.odl-order-summary .odl-head span { color: var(--ds-color-text-secondary); font: var(--ds-text-body-sm); }
.odl-order-summary ul { margin: 0; padding: 0; list-style: none; display: grid; }
.odl-order-summary .odl-item { display: grid; grid-template-columns: var(--ds-size-control-md) minmax(0, 1fr) auto; column-gap: var(--ds-space-inline-sm); row-gap: var(--ds-space-stack-xs);
  padding-block: var(--ds-space-stack-sm); }
.odl-order-summary .odl-item + .odl-item { border-block-start: var(--ds-border-width-default) solid var(--ds-color-border-subtle); }
.odl-order-summary .odl-item:first-child { padding-block-start: 0; }
.odl-order-summary .odl-thumb { grid-row: span 2; display: grid; place-items: center; inline-size: var(--ds-size-control-md); block-size: var(--ds-size-control-md);
  border-radius: var(--ds-radius-nested); background: var(--ds-color-bg-accent-subtle); color: var(--ds-color-icon-accent); }
.odl-order-summary .odl-thumb svg { inline-size: var(--ds-size-icon-md); block-size: var(--ds-size-icon-md); }
.odl-order-summary .odl-name { display: grid; min-inline-size: 0; }
.odl-order-summary .odl-name b { font: var(--ds-text-label-lg); font-weight: var(--ds-font-weight-heading); }
.odl-order-summary .odl-name small { color: var(--ds-color-text-secondary); font: var(--ds-text-body-sm); font-variant-numeric: tabular-nums; }
.odl-order-summary .odl-line { font-variant-numeric: tabular-nums; text-align: end; }
.odl-order-summary .odl-step { grid-column: 2 / -1; justify-self: start; display: inline-flex; align-items: center; border: var(--ds-border-width-default) solid var(--ds-color-border-default);
  border-radius: var(--ds-radius-control); background: var(--ds-color-surface-raised); }
.odl-order-summary .odl-step button { display: grid; place-items: center; min-inline-size: var(--ds-size-target-min); min-block-size: var(--ds-size-target-min); padding: 0;
  border: 0; border-radius: var(--ds-radius-control); background: transparent; color: var(--ds-color-text-primary); cursor: pointer;
  transition: background-color var(--ds-motion-duration-short) var(--ds-motion-easing-standard); }
.odl-order-summary .odl-step button:hover:not(:disabled) { background: var(--ds-color-bg-neutral-subtle); }
.odl-order-summary .odl-step button:disabled { color: var(--ds-color-text-disabled); cursor: not-allowed; }
.odl-order-summary .odl-step svg { inline-size: var(--ds-size-icon-sm); block-size: var(--ds-size-icon-sm); }
.odl-order-summary .odl-step output { min-inline-size: 3ch; text-align: center; font: var(--ds-text-label-lg); font-variant-numeric: tabular-nums; }
.odl-order-summary .odl-promo { display: grid; gap: var(--ds-space-stack-xs); }
.odl-order-summary .odl-lab { color: var(--ds-color-text-secondary); font: var(--ds-text-label-md); }
.odl-order-summary .odl-field { display: flex; gap: var(--ds-space-inline-xs); }
.odl-order-summary input { flex: 1; min-inline-size: 0; min-block-size: max(var(--ds-size-control-md), var(--ds-size-target-min)); padding: 0 var(--ds-space-inset-sm);
  border: var(--ds-border-width-default) solid var(--ds-color-border-input); border-radius: var(--ds-radius-control); background: var(--ds-color-bg-field); color: var(--ds-color-text-primary);
  font: var(--ds-text-body-md); text-transform: uppercase; }
.odl-order-summary input::placeholder { color: var(--ds-color-text-tertiary); text-transform: none; }
.odl-order-summary input[aria-invalid="true"] { border-color: var(--ds-color-border-danger); }
.odl-order-summary .odl-apply { min-block-size: max(var(--ds-size-control-md), var(--ds-size-target-min)); padding: 0 var(--ds-space-inset-md); border: var(--ds-border-width-default) solid var(--ds-color-border-default);
  border-radius: var(--ds-radius-control); background: var(--ds-color-surface-raised); color: var(--ds-color-text-primary); font: var(--ds-text-label-lg); cursor: pointer;
  transition: background-color var(--ds-motion-duration-short) var(--ds-motion-easing-standard); }
.odl-order-summary .odl-apply:hover { background: var(--ds-color-bg-neutral-subtle); }
.odl-order-summary .odl-msg { margin: 0; color: var(--ds-color-text-danger); font: var(--ds-text-body-sm); }
.odl-order-summary .odl-msg:empty { display: none; }
.odl-order-summary .odl-chip { justify-self: start; display: inline-flex; align-items: center; gap: var(--ds-space-inline-xs); padding-inline-start: var(--ds-space-inset-sm);
  border-radius: var(--ds-radius-control-sm); background: var(--ds-color-bg-success-subtle); color: var(--ds-color-text-success); font: var(--ds-text-label-md); }
.odl-order-summary .odl-chip[hidden] { display: none; }
.odl-order-summary .odl-chip code { font: var(--ds-text-code-sm); font-weight: var(--ds-font-weight-label); }
.odl-order-summary .odl-chip svg { inline-size: var(--ds-size-icon-sm); block-size: var(--ds-size-icon-sm); }
.odl-order-summary .odl-chip button { display: grid; place-items: center; min-inline-size: var(--ds-size-target-min); min-block-size: var(--ds-size-target-min); padding: 0; margin-block: calc(-1 * var(--ds-space-8));
  border: 0; border-radius: var(--ds-radius-full); background: transparent; color: inherit; cursor: pointer; }
.odl-order-summary .odl-chip button:hover { color: var(--ds-color-text-primary); }
.odl-order-summary dl { margin: 0; display: grid; gap: var(--ds-space-stack-xs); padding-block-start: var(--ds-space-stack-md); border-block-start: var(--ds-border-width-default) solid var(--ds-color-border-subtle);
  font-variant-numeric: tabular-nums; }
.odl-order-summary dl div { display: flex; justify-content: space-between; gap: var(--ds-space-inline-md); }
.odl-order-summary dt { color: var(--ds-color-text-secondary); }
.odl-order-summary dd { margin: 0; text-align: end; }
.odl-order-summary .odl-off dd { color: var(--ds-color-text-success); }
.odl-order-summary .odl-off[hidden] { display: none; }
.odl-order-summary .odl-total { align-items: baseline; margin-block-start: var(--ds-space-stack-xs); padding-block-start: var(--ds-space-stack-sm); border-block-start: var(--ds-border-width-default) solid var(--ds-color-border-subtle); }
.odl-order-summary .odl-total dt { color: var(--ds-color-text-primary); font: var(--ds-text-label-lg); font-weight: var(--ds-font-weight-heading); }
.odl-order-summary .odl-total dd { font: var(--ds-text-numeric-md); font-weight: var(--ds-font-weight-heading); }
.odl-order-summary .odl-total dd small { margin-inline-start: var(--ds-space-4); color: var(--ds-color-text-tertiary); font: var(--ds-text-label-sm); }
.odl-order-summary .odl-pay { display: inline-flex; align-items: center; justify-content: center; gap: var(--ds-space-inline-xs); inline-size: 100%;
  min-block-size: max(var(--ds-size-control-lg), var(--ds-size-target-min)); padding: 0 var(--ds-space-inset-md); border: 0; border-radius: var(--ds-radius-control);
  background: var(--ds-color-bg-action-primary); color: var(--ds-color-text-on-action); font: var(--ds-text-label-lg); font-weight: var(--ds-font-weight-heading); font-variant-numeric: tabular-nums; cursor: pointer;
  transition: background-color var(--ds-motion-duration-short) var(--ds-motion-easing-standard); }
.odl-order-summary .odl-pay:hover { background: var(--ds-color-bg-action-primary-hover); }
.odl-order-summary .odl-pay:active { background: var(--ds-color-bg-action-primary-pressed); }
.odl-order-summary .odl-pay svg { inline-size: var(--ds-size-icon-sm); block-size: var(--ds-size-icon-sm); }
.odl-order-summary .odl-fine { margin: calc(-1 * var(--ds-space-stack-sm)) 0 0; color: var(--ds-color-text-secondary); font: var(--ds-text-body-sm); text-align: center; text-wrap: balance; }
.odl-order-summary button:focus-visible, .odl-order-summary input:focus-visible { outline: var(--ds-focus-ring-width) solid var(--ds-color-border-focus); outline-offset: var(--ds-focus-ring-offset); }
@container (max-width: 22rem) {
  .odl-order-summary .odl-card { padding: var(--ds-space-inset-md); }
  .odl-order-summary .odl-item { grid-template-columns: minmax(0, 1fr) auto; }
  .odl-order-summary .odl-thumb { display: none; }
  .odl-order-summary .odl-step { grid-column: 1 / -1; }
}
@media (prefers-reduced-motion: reduce) { .odl-order-summary, .odl-order-summary *, .odl-order-summary *::before { transition: none !important; animation: none !important; } }
</style>
<section class="odl-order-summary" aria-label="Order summary">
  <div class="odl-card">
    <div class="odl-head"><h3>Order summary</h3><span>Oskarby Analytics</span></div>
    <ul>
      <li class="odl-item" data-price="48" data-unit="seat" data-units="seats">
        <span class="odl-thumb" aria-hidden="true"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="7.5" cy="7" r="2.75"/><path d="M2.5 16c.6-2.6 2.6-4 5-4s4.4 1.4 5 4"/><path d="M13 4.5a2.5 2.5 0 0 1 0 5M15 12.4c1.3.6 2.2 1.8 2.5 3.6"/></svg></span>
        <span class="odl-name"><b>Extra seats</b><small>$48.00 per seat a month</small></span>
        <span class="odl-line">$96.00</span>
        <div class="odl-step" role="group" aria-label="Extra seats quantity">
          <button type="button" data-d="-1" aria-label="One seat fewer"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M3.5 8h9"/></svg></button>
          <output aria-live="polite">2</output>
          <button type="button" data-d="1" aria-label="One seat more"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M3.5 8h9M8 3.5v9"/></svg></button>
        </div>
      </li>
      <li class="odl-item" data-price="250" data-unit="pack" data-units="packs">
        <span class="odl-thumb" aria-hidden="true"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"><path d="M11 2.5 4.5 11h5l-1 6.5L15.5 9h-5z"/></svg></span>
        <span class="odl-name"><b>Usage credit, $250 pack</b><small>Used before card charges; never expires</small></span>
        <span class="odl-line">$500.00</span>
        <div class="odl-step" role="group" aria-label="Usage credit quantity">
          <button type="button" data-d="-1" aria-label="One pack fewer"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M3.5 8h9"/></svg></button>
          <output aria-live="polite">2</output>
          <button type="button" data-d="1" aria-label="One pack more"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M3.5 8h9M8 3.5v9"/></svg></button>
        </div>
      </li>
    </ul>
    <div class="odl-promo">
      <span class="odl-lab">Promo code</span>
      <div class="odl-field">
        <input type="text" aria-label="Promo code" autocomplete="off" spellcheck="false" placeholder="Enter a code">
        <button type="button" class="odl-apply">Apply</button>
      </div>
      <p class="odl-msg" role="alert"></p>
      <span class="odl-chip"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round" aria-hidden="true"><path d="M8.6 1.75h5.65V7.4L7.4 14.25 1.75 8.6z"/><circle cx="11" cy="5" r=".9"/></svg>
        <span><code>AUTUMN15</code> · 15% off</span>
        <button type="button" class="odl-remove" aria-label="Remove code AUTUMN15"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="m4.5 4.5 7 7M11.5 4.5l-7 7"/></svg></button></span>
    </div>
    <dl>
      <div><dt>Subtotal</dt><dd class="odl-sub">$596.00</dd></div>
      <div class="odl-off"><dt>Discount, 15%</dt><dd class="odl-disc">−$89.40</dd></div>
      <div><dt>Sales tax, 8.25%</dt><dd class="odl-tax">$41.79</dd></div>
      <div class="odl-total"><dt>Due today</dt><dd><span class="odl-sum">$548.39</span><small>USD</small></dd></div>
    </dl>
    <button type="button" class="odl-pay"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><rect x="3" y="7" width="10" height="7" rx="1.5"/><path d="M5.25 7V5a2.75 2.75 0 0 1 5.5 0v2"/></svg>Pay <span class="odl-paysum">$548.39</span></button>
    <p class="odl-fine">Charged to the card ending 2861. Seats renew on Nov 1.</p>
  </div>
</section>
<script>
document.querySelectorAll(".odl-order-summary").forEach((root) => {
  if (root.dataset.odlReady) return; // wire once, even if the file is pasted twice
  root.dataset.odlReady = "1";
  const CODE = "AUTUMN15", RATE = 0.15, TAX = 0.0825;
  const money = (n) => "$" + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  const $ = (s) => root.querySelector(s);
  const input = $("input"), msg = $(".odl-msg"), chip = $(".odl-chip");
  let applied = true;
  const update = () => {
    let sub = 0;
    root.querySelectorAll(".odl-item").forEach((item) => {
      const q = Number(item.querySelector("output").textContent), line = q * Number(item.dataset.price);
      sub += line;
      item.querySelector(".odl-line").textContent = money(line);
      item.querySelector('[data-d="-1"]').disabled = q <= 1;
      item.querySelector('[data-d="1"]').disabled = q >= 20;
    });
    const disc = applied ? Math.round(sub * RATE * 100) / 100 : 0;
    const tax = Math.round((sub - disc) * TAX * 100) / 100, total = sub - disc + tax;
    $(".odl-sub").textContent = money(sub);
    $(".odl-disc").textContent = "−" + money(disc);
    $(".odl-off").hidden = !applied;
    chip.hidden = !applied;
    $(".odl-tax").textContent = money(tax);
    $(".odl-sum").textContent = money(total);
    $(".odl-paysum").textContent = money(total);
  };
  root.querySelectorAll(".odl-step button").forEach((b) => b.addEventListener("click", () => {
    const out = b.parentElement.querySelector("output");
    out.textContent = Math.min(20, Math.max(1, Number(out.textContent) + Number(b.dataset.d)));
    update();
  }));
  $(".odl-remove").addEventListener("click", () => { applied = false; update(); input.focus(); });
  const apply = () => {
    const code = input.value.trim().toUpperCase();
    if (!code) return;
    const ok = code === CODE;
    msg.textContent = ok ? "" : `${code} isn't a valid code. Check it and try again.`;
    input.setAttribute("aria-invalid", String(!ok));
    if (ok) { applied = true; input.value = ""; update(); }
  };
  $(".odl-apply").addEventListener("click", apply);
  input.addEventListener("keydown", (e) => { if (e.key === "Enter") apply(); });
  update();
});
</script>

More like this

B2BFriendly · SaaS

Plan picker

Three plans as cards you select, with a monthly or yearly switch that changes the prices and one plan marked as the common choice.

B2BFriendly · SaaS

Product card

A card for a digital product or plan add-on: a cover drawn from the tokens, name, one-line description, rating, price with the old price struck out, an Add button and a save toggle.

B2BQuiet · Finance

Stat strip

Four headline numbers in one band, each with a plain note under it, and a small bar where a share matters.

Your kit

Nothing here yet. Add parts with Add to kit, and a look if you want the whole system.

    Parts
    0
    Files to fetch
    0 KB
    Licence
    MIT
    Total
    Free, now and later

    How do you want it?

    Your prompt

    No sign-up. Nothing leaves your browser until you paste it.

    Free