less than a minute read • Updated

Create a Gift Card Purchase Form in Webstudio

This tutorial shows Webstudio users how to build a working Foxy gift card purchase form


Overview

This tutorial shows how to build a minimal and an advanced add-to-cart form that sells digital gift cards.


Demo


Create a Gift Card in Foxy

In Foxy, “gift cards” are configured in the Foxy admin and issued as gift card codes that maintain a balance. A gift card code is what a customer redeems at checkout, and it can be reused until its balance reaches zero.

Operationally, selling a gift card is just selling a product that is associated with a specific item category and gift card provisioning rules. Item categories can be configured to send a “gift recipient” email using a dedicated gift recipient email template setting.

Before going further review our gift card docs here.

Once you have created your gift card, setup your gift card email, and saved your gift card SKU you can continue.


The simplest Webstudio Gift Card form

A minimal Webhook form that only asks for:

  • Recipient email (where the gift card email will be delivered)

  • Amount (a free number input)

Follow these steps:

  1. 1

    Add a Webhook component to the page (this is your form).

  2. 2

    With the Webhook selected, set:

    • Method: POST

    • Action: https://YOUR-STOREDOMAIN.foxycart.com/cart

    • Add hidden inputs to the form (copy/paste):

      <input type="hidden" name="name" value="Gift Card" />
      <input type="hidden" name="code" value="gift_card_<SKU>" />
      <input type="hidden" name="category" value="gift_card" />

    Notes:

    • Replace with your gift card product code (SKU).

    • Only include the category input if your configuration requires it.

  3. 3

    Add a visible Email input

    • Label: Recipient Email Address

    • id: gift_recipient_email

    • name: gift_recipient_email

    • type: email

    • required: true

  4. 4

    Add a visible Number input:

    • Label: Amount

    • id: price

    • name: price

    • type: number

    • required: true

    • (optional) min/max to match your provisioning rules

  5. 5

    Add a Submit button: “Add to cart”.


Advanced dynamic Gift Card form

This advanced gift card purchase form creates a Foxy add-to-cart experience on a Webstudio site using a Webhook form that posts directly to your Foxy cart. Customers can choose whether the gift card is for themselves or “Someone Else.” If they choose “Someone Else,” the form reveals additional fields for the recipient’s name, the sender’s name, and an optional message.

The customer then selects a preset amount or chooses “Custom” to enter a different amount. The included script automatically sets the item price and updates the Foxy product code to gift_card_<SKU> (based on the selected amount), ensuring the correct gift card SKU is added to the cart. The recipient email address is always required so Foxy can deliver the gift card by email.

You can copy and paste this code inside the Webstudio page:

<form
  foxy-form
  action="https://YOUR-STOREDOMAIN.foxycart.com/cart"
  method="post"
  class="gift-card-form"
>
  <!-- Required hidden fields -->
  <input type="hidden" name="name" value="Gift Card" />
  <!-- IMPORTANT: code is the SKU identifier (gift_card_<SKU>). Script will overwrite based on amount. -->
  <input type="hidden" name="code" value="gift_card_GC50" />
  <!-- Include category only if your setup requires it -->
  <input type="hidden" name="category" value="gift_card" />

  <!-- Who is this for? -->
  <div class="form-section">
    <label for="who_is_this_for">Who is this for?</label>
    <select id="who_is_this_for" name="who_is_this_for">
      <!-- Text matters because script reads the visible option text -->
      <option value="">Myself</option>
      <option value="">Someone Else</option>
    </select>
  </div>

  <!-- Recipient name (shown only when Someone Else) -->
  <div class="form-section" style="display: none;">
    <label for="shipto">Recipient's name</label>
    <input
      type="text"
      id="shipto"
      name="shipto"
      placeholder="Who is receiving this gift?"
      maxlength="256"
    />
  </div>

  <!-- Sender name (shown only when Someone Else) -->
  <div class="form-section" style="display: none;">
    <label for="from">Your name</label>
    <input
      type="text"
      id="from"
      name="from"
      placeholder="Who is sending this gift?"
      maxlength="256"
    />
  </div>

  <!-- Recipient email (always shown + required) -->
  <div class="form-section">
    <label for="gift_recipient_email">Recipient Email Address</label>
    <input
      type="email"
      id="gift_recipient_email"
      name="gift_recipient_email"
      placeholder="Where do you want the digital voucher emailed to?"
      required
      maxlength="256"
    />
  </div>

  <!-- Message (optional; shown only when Someone Else) -->
  <div class="form-section" style="display: none;">
    <label for="gift_recipient_message">Message (optional)</label>
    <textarea
      id="gift_recipient_message"
      name="gift_recipient_message"
      maxlength="5000"
    ></textarea>
  </div>

  <!-- Amount selector -->
  <div class="form-section">
    <label for="price-select">Amount</label>
    <!-- x:amount stores the chosen denomination as a line-item option -->
    <select id="price-select" name="x:amount" required>
      <option value="50">€50</option>
      <option value="100">€100</option>
      <option value="150">€150</option>
      <option value="200">€200</option>
      <option value="250">€250</option>
      <option value="300">€300</option>
      <option value="350">€350</option>
      <option value="400">€400</option>
      <option value="450">€450</option>
      <option value="500">€500</option>
      <option value="custom">Custom</option>
    </select>
  </div>

  <!-- Custom amount (only shown when Amount = Custom) -->
  <div id="price-custom" class="form-section" style="display: none;">
    <label for="price-input">Custom Amount</label>
    <!-- This MUST be name="price" so Foxy uses it as the line-item price -->
    <input
      type="number"
      id="price-input"
      name="price"
      min="1"
      step="1"
      inputmode="decimal"
    />
  </div>

  <button type="submit">Add to cart</button>
</form>

<script>
  const form =
    document.querySelector('form[foxy-form]') || document.querySelector('form');

  // --- Elements ---------------------------------------------------------
  const whoIsThisFor = form.querySelector('#who_is_this_for');
  const shipto = form.querySelector('#shipto');
  const from = form.querySelector('#from');
  const recipientEmail = form.querySelector('#gift_recipient_email');
  const recipientMessage = form.querySelector('#gift_recipient_message');

  const priceSelect = form.querySelector('#price-select');
  const priceInput = form.querySelector('#price-input'); // name="price"
  const priceCustomWrap = document.getElementById('price-custom');

  const codeInput = form.querySelector('input[name="code"]');

  // --- Map denomination -> SKU (recommended if SKU != amount) -----------
  // IMPORTANT: `code` must be gift_card_<SKU> (SKU is the product code in Foxy)
  // If your SKUs are literally "50", "100", etc., you can use { "50":"50", ... }.
  const skuByAmount = {
    '50': 'GC50',
    '100': 'GC100',
    '150': 'GC150',
    '200': 'GC200',
    '250': 'GC250',
    '300': 'GC300',
    '350': 'GC350',
    '400': 'GC400',
    '450': 'GC450',
    '500': 'GC500',
  };

  // --- Helpers ----------------------------------------------------------
  const setRequired = (el, required) => {
    if (!el) return;
    el.required = !!required;
    if (required) el.setAttribute('required', '');
    else el.removeAttribute('required');
  };

  const showSection = (el, show) => {
    if (!el) return;
    const section = el.closest('.form-section') || el.parentElement;
    if (section) section.style.display = show ? 'block' : 'none';
    if (!show) el.value = '';
  };

  const getWhoText = () => {
    if (!whoIsThisFor) return '';
    return (
      whoIsThisFor.options?.[whoIsThisFor.selectedIndex]?.text?.trim() || ''
    );
  };

  // --- Myself vs Someone Else ------------------------------------------
  const updateRecipientFields = () => {
    const whoText = getWhoText();
    const isSomeoneElse = whoText.toLowerCase() === 'someone else';

    showSection(shipto, isSomeoneElse);
    setRequired(shipto, isSomeoneElse);

    showSection(from, isSomeoneElse);
    setRequired(from, isSomeoneElse);

    showSection(recipientMessage, isSomeoneElse);
    setRequired(recipientMessage, false);

    // Always show + require recipient email
    showSection(recipientEmail, true);
    setRequired(recipientEmail, true);
  };

  // --- Amount + custom amount + code -----------------------------------
  const updatePriceAndCode = () => {
    if (!priceSelect) return;

    const selected = priceSelect.value;

    if (selected !== 'custom') {
      if (priceCustomWrap) priceCustomWrap.style.display = 'none';

      // Set the price to the selected denomination (still submits via name="price")
      if (priceInput) priceInput.value = selected;
      setRequired(priceInput, false);

      // Set code = gift_card_<SKU>
      const sku = skuByAmount[selected] || selected;
      if (codeInput) codeInput.value = 'gift_card_' + sku;
    } else {
      if (priceCustomWrap) priceCustomWrap.style.display = 'block';

      // Custom price must be entered by user
      if (priceInput) priceInput.value = '';
      setRequired(priceInput, true);

      // If you have a single SKU for custom amounts, use it here:
      // codeInput.value = 'gift_card_<YOUR_CUSTOM_SKU>';
      if (codeInput) codeInput.value = 'gift_card_custom';
    }
  };

  // --- Init -------------------------------------------------------------
  updateRecipientFields();
  updatePriceAndCode();

  // --- Listeners --------------------------------------------------------
  if (whoIsThisFor)
    whoIsThisFor.addEventListener('change', updateRecipientFields);
  if (priceSelect) priceSelect.addEventListener('change', updatePriceAndCode);
</script>

Notes: what you must adapt/change

  1. 1

    Store domain: Replace https://YOUR-STOREDOMAIN.foxycart.com/cart with your real Foxy store domain. Example: https:/your-store-domain.foxycart.com/cart.

  2. 2

    SKU mapping (most important): Update skuByAmount to match your real gift card SKUs in Foxy. The script sets code to gift_card_<SKU>, and the suffix must be a real SKU.

  3. 3

    Custom amount behavior: Decide how “Custom” should work. If custom amounts should still sell a real SKU, replace gift_card_custom with gift_card_<YOUR_CUSTOM_SKU>.

  4. 4

    Category field: Only keep <input type="hidden" name="category" value="gift_card" /> if your store configuration expects it. If you don’t need it, remove it.


Need Help?

Did this article answer your questions? Need help with anything? Please click below to contact us.