T-Shirt Pricing Calculator

Description

09.26c14v1(v4) T Shirt Pricing Calculator

#1. Install Code

You can use an AI to tweak the code. You can also use this Calculator widget (free) if you need more style/options

#1.1. You can add a Code Block with this code

<!-- 09.26c14v1(v4) T-Shirt Pricing Calculator -->
<div class="tp-calc" data-tp-tshirt></div>

<script>
  window.TShirtPricingCalcConfig = {
    text: {
      title: "",
      quantityLabel: "Number of T-Shirts",
      quantityHint: "Select the number of T-shirts you want to order.",
      typeLabel: "Choose T-Shirt Type",
      typeHint: "Select the type of T-shirt.",
      printingLabel: "Choose Printing Option",
      printingHint: "Select the type of printing option.",
      totalHeading: "Total Cost",
      totalHint: "The total cost for your order.",
      unitPriceLabel: "Price per T-Shirt",
      unitPriceHint: "Unit price of one T-shirt.",
      discountLabel: "Discount",
      discountHint: "Discount applied to your total order.",
      ctaHeading: "Order Your Customized T-Shirts Now!",
      ctaHint: "Take advantage of our competitive pricing and place your order today!",
      ctaButton: "Place Order",
      ctaHref: "/contact-us"
    },
    tags: {
      title: "h2",
      quantityLabel: "h3",
      typeLabel: "h3",
      printingLabel: "h3",
      totalHeading: "h3",
      unitPriceLabel: "h4",
      discountLabel: "h4",
      ctaHeading: "h2"
    },
    colors: {
      title: "",
      label: "",
      smallText: "",
      cardBg: "#e9f5ec",
      cardHeading: "#111111",
      cardValue: "#111111",
      cardMuted: "rgba(17,17,17,0.55)"
    },
    slider: {
      trackFill: "#2f8132",
      trackEmpty: "rgba(17,17,17,0.05)",
      thumbBg: "#ffffff",
      thumbBorder: "rgba(17,17,17,0.1)",
      trackHeight: "6px",
      thumbSize: "24px"
    },
    layout: {
      inputBorder: "1px solid rgba(17,17,17,0.2)"
    },
    button: {
      text: "#ffffff",
      bg: "#2f8132",
      border: "#2f8132",
      hoverText: "#ffffff",
      hoverBg: "#276b29",
      hoverBorder: "#276b29"
    },
    ranges: {
      quantity: { min: 1, max: 200, step: 1, value: 1 }
    },
    types: [
      { label: "Basic", price: 10 },
      { label: "Premium", price: 18 },
      { label: "Organic", price: 22 }
    ],
    printing: [
      { label: "None", price: 0 },
      { label: "Single Slide", price: 3 },
      { label: "Double Slide", price: 5 }
    ],
    discountTiers: [
      { minQty: 1, rate: 0 },
      { minQty: 25, rate: 0.05 },
      { minQty: 50, rate: 0.10 },
      { minQty: 100, rate: 0.15 }
    ],
    formula: {
      currencySymbol: "$",
      moneyDecimals: 0,
      percentDecimals: 1,
      totalFn: null
    }
  };
</script>

<script>
  (function () {
    var CFG = window.TShirtPricingCalcConfig;

    var CSS =
      ".tp-calc,.tp-calc *{box-sizing:border-box}" +
      ".tp-calc{--tp-card-bg:#e9f5ec;--tp-track-fill:#2f8132;--tp-track-empty:rgba(17,17,17,0.05);--tp-thumb-bg:#fff;--tp-thumb-border:rgba(17,17,17,0.1);--tp-track-h:6px;--tp-thumb-size:24px;--tp-input-border:1px solid rgba(17,17,17,0.2);--tp-card-radius:22px;color:inherit}" +
      ".tp-calc__wrap{max-width:1180px;margin:40px auto;padding:0 24px;display:grid;grid-template-columns:1.1fr 0.9fr;gap:48px;align-items:start}" +
      ".tp-calc__h{margin:0}" +
      ".tp-calc__title{margin:0 0 32px}" +
      ".tp-calc__field{padding:14px 0}" +
      ".tp-calc__labelRow{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:18px}" +
      ".tp-calc__sm{margin:14px 0 0}" +
      ".tp-calc__pill{min-width:var(--tp-pill-min-width,64px);background:#fff;border:var(--tp-input-border);border-radius:12px;padding:12px 16px;display:inline-flex;align-items:center;justify-content:center;font-size:17px;color:#111}" +
      ".tp-calc__num{width:auto;min-width:1ch;border:0;background:transparent;padding:0;margin:0;color:inherit;text-align:center}" +
      ".tp-calc__unit{margin-left:6px}" +
      ".tp-calc__unit--tight{margin-left:2px}" +
      ".tp-calc__range{width:100%;-webkit-appearance:none;appearance:none;height:var(--tp-track-h);border-radius:999px;margin:4px 0 0;cursor:pointer;background:linear-gradient(90deg,var(--tp-track-fill) 0%,var(--tp-track-fill) var(--tp-fill,0%),var(--tp-track-empty) var(--tp-fill,0%),var(--tp-track-empty) 100%)}" +
      ".tp-calc__range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:var(--tp-thumb-size);height:var(--tp-thumb-size);border-radius:50%;background:var(--tp-thumb-bg);border:1px solid var(--tp-thumb-border);box-shadow:0 2px 6px rgba(0,0,0,.15);cursor:pointer}" +
      ".tp-calc__range::-moz-range-thumb{width:var(--tp-thumb-size);height:var(--tp-thumb-size);border-radius:50%;background:var(--tp-thumb-bg);border:1px solid var(--tp-thumb-border);box-shadow:0 2px 6px rgba(0,0,0,.15);cursor:pointer}" +
      ".tp-calc__minmax{display:flex;justify-content:space-between;margin-top:12px}" +
      ".tp-calc__selectWrap{position:relative;margin-top:4px}" +
      ".tp-calc__selectWrap::after{content:'';position:absolute;right:20px;top:50%;width:9px;height:9px;border-right:2px solid #111;border-bottom:2px solid #111;transform:translateY(-70%) rotate(45deg);pointer-events:none}" +
      ".tp-calc__select{width:100%;-webkit-appearance:none;appearance:none;border:var(--tp-input-border);border-radius:12px;padding:16px 46px 16px 18px;line-height:1.2;background:#fff;color:#111;cursor:pointer;font:inherit;font-size:18px}" +
      ".tp-calc__select:focus{outline:none}" +
      ".tp-calc__card{width:100%;background:var(--tp-card-bg);border-radius:var(--tp-card-radius);padding:44px}" +
      ".tp-calc__card .tp-calc__h{margin:0 0 4px}" +
      ".tp-calc__total{font-size:60px;line-height:1;margin:10px 0 6px}" +
      ".tp-calc__etaRow{display:flex;justify-content:space-between;align-items:flex-start;gap:16px}" +
      ".tp-calc__etaVal{font-size:22px;white-space:nowrap}" +
      ".tp-calc__spacer{height:26px}" +
      ".tp-calc__spacer--lg{height:40px}" +
      ".tp-calc a.tp-calc__btn{display:block !important;width:100% !important;text-align:center !important;border-radius:10px !important;margin-top:20px}" +
      "@media (max-width:980px){.tp-calc__wrap{grid-template-columns:1fr;gap:28px}.tp-calc__card{padding:34px}}" +
      "@media (max-width:520px){.tp-calc__card{padding:28px}.tp-calc__total{font-size:52px}}";

    function decl(prop, val) { return val ? prop + ":" + val + " !important;" : ""; }

    function buttonCSS() {
      var B = CFG.button;
      var base = decl("color", B.text) + decl("background-color", B.bg) + decl("border-color", B.border);
      var hover = decl("color", B.hoverText) + decl("background-color", B.hoverBg) + decl("border-color", B.hoverBorder);
      var out = "";
      if (base) out += ".tp-calc a.tp-calc__btn{" + base + "}";
      if (hover) out += ".tp-calc a.tp-calc__btn:hover{" + hover + "}";
      return out;
    }

    function injectCSS() {
      if (window.__tshirtPricingCalcStyled) return;
      window.__tshirtPricingCalcStyled = true;
      var st = document.createElement("style");
      st.type = "text/css";
      st.textContent = CSS + buttonCSS();
      document.head.appendChild(st);
    }

    function el(tag, cls, txt) {
      var e = document.createElement(tag);
      if (cls) e.className = cls;
      if (txt != null) e.textContent = txt;
      return e;
    }

    function heading(tag, txt, color) {
      var e = el(tag, "tp-calc__h", txt);
      if (color) e.style.color = color;
      return e;
    }

    function smallP(txt, color) {
      var e = el("p", "sqsrte-small tp-calc__sm", txt);
      if (color) e.style.color = color;
      return e;
    }

    function stepDecimals(step) {
      var s = String(step);
      var i = s.indexOf(".");
      return i < 0 ? 0 : (s.length - i - 1);
    }

    function fmtNumber(v, decimals) {
      return (+v).toLocaleString("en-US", { minimumFractionDigits: 0, maximumFractionDigits: decimals });
    }

    function formatMoney(n) {
      var F = CFG.formula;
      var d = Math.max(0, F.moneyDecimals | 0);
      return F.currencySymbol + (+n).toLocaleString("en-US", { minimumFractionDigits: d, maximumFractionDigits: d });
    }

    function formatPercent(rate) {
      var d = Math.max(0, CFG.formula.percentDecimals | 0);
      return (rate * 100).toLocaleString("en-US", { minimumFractionDigits: d, maximumFractionDigits: d }) + "%";
    }

    function discountFor(qty) {
      var tiers = CFG.discountTiers, rate = 0;
      for (var i = 0; i < tiers.length; i++) {
        if (qty >= tiers[i].minQty) rate = tiers[i].rate;
      }
      return rate;
    }

    function clampNum(v, min, max, decimals) {
      v = +v;
      if (!isFinite(v)) v = min;
      v = Math.min(max, Math.max(min, v));
      var f = Math.pow(10, decimals || 0);
      return Math.round(v * f) / f;
    }

    var measureSpan;
    function autosize(input) {
      if (!measureSpan) {
        measureSpan = document.createElement("span");
        measureSpan.style.cssText = "position:absolute;visibility:hidden;white-space:pre;left:-9999px;top:0";
        document.body.appendChild(measureSpan);
      }
      var cs = window.getComputedStyle(input);
      measureSpan.style.fontFamily = cs.fontFamily;
      measureSpan.style.fontSize = cs.fontSize;
      measureSpan.style.fontWeight = cs.fontWeight;
      measureSpan.style.fontStyle = cs.fontStyle;
      measureSpan.style.letterSpacing = cs.letterSpacing;
      measureSpan.textContent = input.value || "0";
      input.style.width = (measureSpan.offsetWidth + 2) + "px";
    }

    function numField(o) {
      var decimals = stepDecimals(o.r.step);
      var node = el("div", "tp-calc__field");
      var row = el("div", "tp-calc__labelRow");
      row.appendChild(heading(o.tag, o.label, CFG.colors.label));

      var pill = el("div", "tp-calc__pill");
      var input = el("input", "tp-calc__num");
      input.type = "text";
      input.setAttribute("inputmode", decimals ? "decimal" : "numeric");
      input.setAttribute("aria-label", o.label);
      pill.appendChild(input);
      if (o.suffix) {
        pill.appendChild(el("span", "tp-calc__unit" + (o.suffixTight ? " tp-calc__unit--tight" : ""), o.suffix));
      }
      row.appendChild(pill);
      node.appendChild(row);

      var range = el("input", "tp-calc__range");
      range.type = "range";
      range.min = o.r.min; range.max = o.r.max; range.step = o.r.step; range.value = o.r.value;
      range.setAttribute("aria-label", o.label);
      node.appendChild(range);

      var mm = el("div", "tp-calc__minmax");
      var s1 = el("span", "sqsrte-small", labelText(o.r.min));
      var s2 = el("span", "sqsrte-small", labelText(o.r.max));
      if (CFG.colors.smallText) { s1.style.color = CFG.colors.smallText; s2.style.color = CFG.colors.smallText; }
      mm.appendChild(s1); mm.appendChild(s2);
      node.appendChild(mm);

      if (o.hint) node.appendChild(smallP(o.hint, CFG.colors.smallText));

      function labelText(v) {
        var s = (o.prefix || "") + fmtNumber(v, decimals);
        if (o.suffix) s += (o.suffixTight ? "" : " ") + o.suffix;
        return s;
      }
      function disp(v) { return (o.prefix || "") + fmtNumber(v, decimals); }
      function get() {
        var cleaned = (input.value || "").replace(/[^0-9.]/g, "");
        var v = cleaned === "" ? o.r.min : parseFloat(cleaned);
        return clampNum(v, o.r.min, o.r.max, decimals);
      }
      function fill() {
        var v = +range.value, min = +range.min, max = +range.max;
        range.style.setProperty("--tp-fill", ((v - min) / (max - min)) * 100 + "%");
      }
      function sync(v) { range.value = v; fill(); autosize(input); }

      var cb = function () {};
      input.addEventListener("input", function () { autosize(input); cb(); });
      input.addEventListener("change", function () { input.value = disp(get()); autosize(input); cb(); });
      range.addEventListener("input", function () { input.value = disp(+range.value); autosize(input); cb(); });

      input.value = disp(o.r.value);
      fill();

      return { node: node, get: get, sync: sync, onChange: function (f) { cb = f; } };
    }

    function selectField(o) {
      var node = el("div", "tp-calc__field");
      node.appendChild(heading(o.tag, o.label, CFG.colors.label));

      var wrap = el("div", "tp-calc__selectWrap");
      var select = el("select", "tp-calc__select");
      select.setAttribute("aria-label", o.label);
      for (var i = 0; i < o.options.length; i++) {
        var opt = el("option", null, o.options[i].label);
        opt.value = i;
        select.appendChild(opt);
      }
      select.value = String(o.value || 0);
      wrap.appendChild(select);
      node.appendChild(wrap);

      if (o.hint) node.appendChild(smallP(o.hint, CFG.colors.smallText));

      var cb = function () {};
      select.addEventListener("change", function () { cb(); });

      return { node: node, get: function () { return +select.value; }, onChange: function (f) { cb = f; } };
    }

    function summaryRow(tag, label, hint) {
      var row = el("div", "tp-calc__etaRow");
      var lft = el("div");
      lft.appendChild(heading(tag, label, CFG.colors.cardHeading));
      if (hint) lft.appendChild(smallP(hint, CFG.colors.cardMuted));
      var val = el("div", "tp-calc__etaVal");
      if (CFG.colors.cardValue) val.style.color = CFG.colors.cardValue;
      row.appendChild(lft); row.appendChild(val);
      return { row: row, val: val };
    }

    function bigTotal(tag, headingText, hint) {
      var frag = document.createDocumentFragment();
      frag.appendChild(heading(tag, headingText, CFG.colors.cardHeading));
      var val = el("div", "tp-calc__total");
      if (CFG.colors.cardValue) val.style.color = CFG.colors.cardValue;
      frag.appendChild(val);
      frag.appendChild(smallP(hint, CFG.colors.cardMuted));
      return { frag: frag, val: val };
    }

    function mount(root) {
      if (!root || root.dataset.tpDone === "1") return;
      root.dataset.tpDone = "1";

      var T = CFG.text, G = CFG.tags, K = CFG.colors, S = CFG.slider, R = CFG.ranges, F = CFG.formula;

      root.style.setProperty("--tp-card-bg", K.cardBg);
      root.style.setProperty("--tp-track-fill", S.trackFill);
      root.style.setProperty("--tp-track-empty", S.trackEmpty);
      root.style.setProperty("--tp-thumb-bg", S.thumbBg);
      root.style.setProperty("--tp-thumb-border", S.thumbBorder);
      root.style.setProperty("--tp-track-h", S.trackHeight);
      root.style.setProperty("--tp-thumb-size", S.thumbSize);
      root.style.setProperty("--tp-input-border", CFG.layout.inputBorder);

      var wrap = el("div", "tp-calc__wrap");
      var left = el("div", "tp-calc__left");
      var right = el("div", "tp-calc__right");

      if (T.title) {
        var title = heading(G.title, T.title, K.title);
        title.classList.add("tp-calc__title");
        left.appendChild(title);
      }

      var quantityField = numField({ label: T.quantityLabel, tag: G.quantityLabel, hint: T.quantityHint, r: R.quantity });
      left.appendChild(quantityField.node);

      var typeField = selectField({ label: T.typeLabel, tag: G.typeLabel, hint: T.typeHint, options: CFG.types, value: 0 });
      left.appendChild(typeField.node);

      var printingField = selectField({ label: T.printingLabel, tag: G.printingLabel, hint: T.printingHint, options: CFG.printing, value: 0 });
      left.appendChild(printingField.node);

      var card = el("div", "tp-calc__card");

      var totalBlock = bigTotal(G.totalHeading, T.totalHeading, T.totalHint);
      card.appendChild(totalBlock.frag);

      card.appendChild(el("div", "tp-calc__spacer tp-calc__spacer--lg"));
      var unitPriceRow = summaryRow(G.unitPriceLabel, T.unitPriceLabel, T.unitPriceHint);
      card.appendChild(unitPriceRow.row);

      card.appendChild(el("div", "tp-calc__spacer"));
      var discountRow = summaryRow(G.discountLabel, T.discountLabel, T.discountHint);
      card.appendChild(discountRow.row);

      card.appendChild(el("div", "tp-calc__spacer tp-calc__spacer--lg"));
      card.appendChild(heading(G.ctaHeading, T.ctaHeading, K.cardHeading));
      card.appendChild(smallP(T.ctaHint, K.cardMuted));

      var btn = el("a", "btn btn--border theme-btn--primary-inverse sqs-button-element--primary tp-calc__btn", T.ctaButton);
      btn.setAttribute("href", T.ctaHref);
      btn.setAttribute("rel", "noopener");
      card.appendChild(btn);

      right.appendChild(card);
      wrap.appendChild(left); wrap.appendChild(right);
      root.appendChild(wrap);

      function recalc() {
        var quantity = quantityField.get(); quantityField.sync(quantity);
        var unitPrice = CFG.types[typeField.get()].price + CFG.printing[printingField.get()].price;
        var subtotal = unitPrice * quantity;
        var discountRate = discountFor(quantity);
        var total = (typeof F.totalFn === "function")
          ? F.totalFn(subtotal, discountRate, unitPrice, quantity, F)
          : subtotal * (1 - discountRate);
        totalBlock.val.textContent = formatMoney(total);
        unitPriceRow.val.textContent = formatMoney(unitPrice);
        discountRow.val.textContent = formatPercent(discountRate);
      }

      quantityField.onChange(recalc);
      typeField.onChange(recalc);
      printingField.onChange(recalc);
      recalc();
    }

    function init() {
      var nodes = document.querySelectorAll("[data-tp-tshirt]");
      for (var i = 0; i < nodes.length; i++) mount(nodes[i]);
    }

    function ready(fn) {
      if (document.readyState !== "loading") fn();
      else document.addEventListener("DOMContentLoaded", fn);
    }

    injectCSS();
    ready(init);

    if (!window.__tshirtPricingCalcBound) {
      window.__tshirtPricingCalcBound = true;
      window.addEventListener("mercury:load", init);
    }
  })();
</script>

09.26c14v1(v4) T Shirt Pricing Calculator

#1.2. Change text, button text, url (line 06 – 24)

text: {
     title: "",
     quantityLabel: "Number of T-Shirts",
     quantityHint: "Select the number of T-shirts you want to order.",
     typeLabel: "Choose T-Shirt Type",
     typeHint: "Select the type of T-shirt.",
     printingLabel: "Choose Printing Option",
     printingHint: "Select the type of printing option.",
     totalHeading: "Total Cost",
     totalHint: "The total cost for your order.",
     unitPriceLabel: "Price per T-Shirt",
     unitPriceHint: "Unit price of one T-shirt.",
     discountLabel: "Discount",
     discountHint: "Discount applied to your total order.",
     ctaHeading: "Order Your Customized T-Shirts Now!",
     ctaHint: "Take advantage of our competitive pricing and place your order today!",
     ctaButton: "Place Order",
     ctaHref: "/contact-us"
   },

#1.3. Change style (line 25 – 62)

tags: {
      title: "h2",
      quantityLabel: "h3",
      typeLabel: "h3",
      printingLabel: "h3",
      totalHeading: "h3",
      unitPriceLabel: "h4",
      discountLabel: "h4",
      ctaHeading: "h2"
    },
    colors: {
      title: "",
      label: "",
      smallText: "",
      cardBg: "#e9f5ec",
      cardHeading: "#111111",
      cardValue: "#111111",
      cardMuted: "rgba(17,17,17,0.55)"
    },
    slider: {
      trackFill: "#2f8132",
      trackEmpty: "rgba(17,17,17,0.05)",
      thumbBg: "#ffffff",
      thumbBorder: "rgba(17,17,17,0.1)",
      trackHeight: "6px",
      thumbSize: "24px"
    },
    layout: {
      inputBorder: "1px solid rgba(17,17,17,0.2)"
    },
    button: {
      text: "#ffffff",
      bg: "#2f8132",
      border: "#2f8132",
      hoverText: "#ffffff",
      hoverBg: "#276b29",
      hoverBorder: "#276b29"
    },

#1.4. Change value of T-Shirt Type, Printing Options, Discount (line 63 – 81)

ranges: {
      quantity: { min: 1, max: 200, step: 1, value: 1 }
    },
    types: [
      { label: "Basic", price: 10 },
      { label: "Premium", price: 18 },
      { label: "Organic", price: 22 }
    ],
    printing: [
      { label: "None", price: 0 },
      { label: "Single Slide", price: 3 },
      { label: "Double Slide", price: 5 }
    ],
    discountTiers: [
      { minQty: 1, rate: 0 },
      { minQty: 25, rate: 0.05 },
      { minQty: 50, rate: 0.10 },
      { minQty: 100, rate: 0.15 }
    ],

#1.5. Change formula (line 82 – 87), you can use AI to write formula for you

formula: {
    currencySymbol: "$",
    moneyDecimals: 0,
    percentDecimals: 1,
    totalFn: null
  }

 

Buy me a coffee