Where you can achieve what your competitors can’t


File Upload Field In Shopify

This custom code is completely free to use, but please note it does not include 1-on-1 technical support. If you need a bespoke, done-for-you solution to customize your Shopify store, my team is here to help! Head to my channel homepage and use the link in the trailer to reach out.

{% comment %}
<!-- Designed by ONHOW Studio - Anas El Medlaoui -->
{% endcomment %}

{%- assign file_accept = 'image/*' -%}
{%- if section.settings.onhow_studio_file_mode == 'pdf' -%}
  {%- assign file_accept = 'application/pdf' -%}
{%- elsif section.settings.onhow_studio_file_mode == 'all' -%}
  {%- assign file_accept = '*' -%}
{%- endif -%}

<div
  id="onhow-studio-upload-config"
  data-mode="{{ section.settings.onhow_studio_file_mode }}"
  data-accept="{{ file_accept }}"
  data-label="{{ section.settings.onhow_studio_property_label | escape }}"
  data-max-size="{{ section.settings.onhow_studio_max_file_size }}"
  data-btn-text="{{ section.settings.onhow_studio_btn_text | escape }}"
  data-helper-text="{{ section.settings.onhow_studio_helper_text | escape }}"
  data-error-type="{{ section.settings.onhow_studio_error_type | escape }}"
  data-error-size="{{ section.settings.onhow_studio_error_size | escape }}"
  data-primary="{{ section.settings.onhow_studio_primary_color }}"
  data-bg="{{ section.settings.onhow_studio_upload_bg_color }}"
  data-radius="{{ section.settings.onhow_studio_border_radius }}"
  data-border-style="{{ section.settings.onhow_studio_border_style }}"
  data-text-input="{{ section.settings.onhow_studio_enable_text_input }}"
  data-text-label="{{ section.settings.onhow_studio_text_input_label | escape }}"
  hidden
></div>

{% schema %}
{
  "name": "OnHOW Upload Config",
  "settings": [
    {
      "type": "header",
      "content": "✨ Built by ONHOW Studio"
    },
    {
      "type": "paragraph",
      "content": "Get free sections & tutorials at youtube.com/@ONHOWStudio"
    },
    {
      "type": "text",
      "id": "onhow_studio_core_logic",
      "label": "Section Architecture (Do Not Edit)",
      "default": "built-by-onhow-studio",
      "info": "Modifying this will break the section's CSS layout."
    },
    {
      "type": "header",
      "content": "Functional"
    },
    {
      "type": "select",
      "id": "onhow_studio_file_mode",
      "label": "File Type",
      "options": [
        { "value": "image", "label": "Image only" },
        { "value": "pdf", "label": "PDF only" },
        { "value": "all", "label": "All files" }
      ],
      "default": "image"
    },
    {
      "type": "text",
      "id": "onhow_studio_property_label",
      "label": "Property Label",
      "default": "Upload File",
      "info": "Appears as the line item property name on the order"
    },
    {
      "type": "range",
      "id": "onhow_studio_max_file_size",
      "label": "Max File Size (MB)",
      "min": 1,
      "max": 50,
      "step": 1,
      "default": 10
    },
    {
      "type": "header",
      "content": "UI Text"
    },
    {
      "type": "text",
      "id": "onhow_studio_btn_text",
      "label": "Browse Button Text",
      "default": "Browse Files"
    },
    {
      "type": "text",
      "id": "onhow_studio_helper_text",
      "label": "Helper Text",
      "default": "Drag & drop or click to upload"
    },
    {
      "type": "text",
      "id": "onhow_studio_error_type",
      "label": "Wrong File Type Message",
      "default": "Invalid file type."
    },
    {
      "type": "text",
      "id": "onhow_studio_error_size",
      "label": "File Too Large Message",
      "default": "File exceeds the maximum size."
    },
    {
      "type": "header",
      "content": "Text Input Field"
    },
    {
      "type": "checkbox",
      "id": "onhow_studio_enable_text_input",
      "label": "Enable text input field",
      "default": false
    },
    {
      "type": "text",
      "id": "onhow_studio_text_input_label",
      "label": "Text Input Label",
      "default": "Special Instructions",
      "info": "Also used as the line item property name on the order"
    },
    {
      "type": "header",
      "content": "Visual"
    },
    {
      "type": "color",
      "id": "onhow_studio_primary_color",
      "label": "Primary Color",
      "default": "#000000"
    },
    {
      "type": "color",
      "id": "onhow_studio_upload_bg_color",
      "label": "Upload Zone Background",
      "default": "#f9f9f9"
    },
    {
      "type": "range",
      "id": "onhow_studio_border_radius",
      "label": "Border Radius (px)",
      "min": 0,
      "max": 20,
      "step": 1,
      "default": 8
    },
    {
      "type": "select",
      "id": "onhow_studio_border_style",
      "label": "Border Style",
      "options": [
        { "value": "dashed", "label": "Dashed" },
        { "value": "solid", "label": "Solid" }
      ],
      "default": "dashed"
    }
  ],
  "presets": [
    {
      "name": "OnHOW Upload Config (By ONHOW Studio)"
    }
  ]
}
{% endschema %}

{% comment %}
<!-- Designed by ONHOW Studio - Anas El Medlaoui -->
{% endcomment %}




Block :

{% comment %}
<!-- Designed by ONHOW Studio - Anas El Medlaoui -->
{% endcomment %}

<div class="onhow-studio-upload-wrapper">
  <div class="onhow-studio-upload-text-group onhow-studio-upload-hidden">
    <label class="onhow-studio-upload-text-label" for="onhow-studio-upload-text-input"></label>
    <input type="text" id="onhow-studio-upload-text-input" class="onhow-studio-upload-text-input" autocomplete="off">
  </div>

  <label class="onhow-studio-upload-label" for="onhow-studio-upload-input"></label>

  <div class="onhow-studio-upload-zone">
    <input
      type="file"
      id="onhow-studio-upload-input"
      class="onhow-studio-upload-input"
    >
    <svg class="onhow-studio-upload-icon" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
      <polyline points="16 16 12 12 8 16"></polyline>
      <line x1="12" y1="12" x2="12" y2="21"></line>
      <path d="M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3"></path>
    </svg>
    <span class="onhow-studio-upload-hint"></span>
    <button type="button" class="onhow-studio-upload-btn"></button>
  </div>

  <div class="onhow-studio-upload-preview onhow-studio-upload-hidden">
    <img class="onhow-studio-upload-img" src="" alt="Uploaded image preview">
    <div class="onhow-studio-upload-card">
      <svg class="onhow-studio-upload-card-icon" xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
        <polyline points="14 2 14 8 20 8"></polyline>
      </svg>
      <div class="onhow-studio-upload-card-info">
        <span class="onhow-studio-upload-card-name"></span>
        <span class="onhow-studio-upload-card-size"></span>
      </div>
    </div>
    <button type="button" class="onhow-studio-upload-remove" aria-label="Remove file">
      <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
        <line x1="18" y1="6" x2="6" y2="18"></line>
        <line x1="6" y1="6" x2="18" y2="18"></line>
      </svg>
    </button>
  </div>

  <p class="onhow-studio-upload-error onhow-studio-upload-hidden" role="alert"></p>
</div>

<style>
  .onhow-studio-upload-wrapper {
    --onhow-studio-upload-primary: #000000;
    --onhow-studio-upload-bg: #f9f9f9;
    --onhow-studio-upload-radius: 8px;
    --onhow-studio-upload-border-style: dashed;
    display: block;
    width: 100%;
    font-family: inherit;
    margin-block: 0;
  }

  .onhow-studio-upload-label {
    display: block;
    font-size: 0.875rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
    color: currentColor;
  }

  .onhow-studio-upload-zone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 1.25rem 1.5rem;
    border: 2px var(--onhow-studio-upload-border-style) rgba(0, 0, 0, 0.2);
    border-radius: var(--onhow-studio-upload-radius);
    background-color: var(--onhow-studio-upload-bg);
    cursor: pointer;
    transition: border-color 0.2s ease, background-color 0.2s ease;
  }

  .onhow-studio-upload-zone:hover {
    border-color: var(--onhow-studio-upload-primary);
  }

  .onhow-studio-upload-zone.onhow-studio-upload-drag-over {
    border-color: var(--onhow-studio-upload-primary);
    background-color: var(--onhow-studio-upload-bg);
    opacity: 0.75;
  }

  .onhow-studio-upload-input {
    display: none;
  }

  .onhow-studio-upload-icon {
    color: var(--onhow-studio-upload-primary);
    opacity: 0.5;
  }

  .onhow-studio-upload-hint {
    font-size: 0.8125rem;
    color: currentColor;
    opacity: 0.55;
    text-align: center;
  }

  .onhow-studio-upload-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.4375rem 1.125rem;
    margin-top: 0.25rem;
    font-size: 0.8125rem;
    font-weight: 600;
    font-family: inherit;
    border: 1.5px solid var(--onhow-studio-upload-primary);
    border-radius: var(--onhow-studio-upload-radius);
    background: transparent;
    color: var(--onhow-studio-upload-primary);
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease;
  }

  .onhow-studio-upload-btn:hover {
    background-color: var(--onhow-studio-upload-primary);
    color: #ffffff;
  }

  .onhow-studio-upload-preview {
    position: relative;
    width: 100%;
    border-radius: var(--onhow-studio-upload-radius);
    overflow: hidden;
  }

  .onhow-studio-upload-img {
    display: block;
    width: 100%;
    height: auto;
    max-height: 280px;
    object-fit: contain;
    border-radius: var(--onhow-studio-upload-radius);
    background-color: var(--onhow-studio-upload-bg);
  }

  .onhow-studio-upload-card {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem;
    border: 2px var(--onhow-studio-upload-border-style) var(--onhow-studio-upload-primary);
    border-radius: var(--onhow-studio-upload-radius);
    background-color: var(--onhow-studio-upload-bg);
  }

  .onhow-studio-upload-card-icon {
    color: var(--onhow-studio-upload-primary);
    flex-shrink: 0;
  }

  .onhow-studio-upload-card-info {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 0;
    flex: 1;
  }

  .onhow-studio-upload-card-name {
    display: block;
    font-size: 0.875rem;
    font-weight: 600;
    color: currentColor;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .onhow-studio-upload-card-size {
    display: block;
    font-size: 0.75rem;
    opacity: 0.55;
    color: currentColor;
  }

  .onhow-studio-upload-remove {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background-color: rgba(0, 0, 0, 0.6);
    color: #ffffff;
    cursor: pointer;
    transition: background-color 0.2s ease;
  }

  .onhow-studio-upload-remove:hover {
    background-color: rgba(0, 0, 0, 0.85);
  }

  .onhow-studio-upload-error {
    margin-top: 0.5rem;
    margin-bottom: 0;
    font-size: 0.8125rem;
    color: #c0392b;
  }

  .onhow-studio-upload-wrapper .onhow-studio-upload-hidden {
    display: none;
  }

  .onhow-studio-upload-text-group {
    margin-bottom: 0.75rem;
  }

  .onhow-studio-upload-text-label {
    display: block;
    font-size: 0.875rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
    color: currentColor;
  }

  .onhow-studio-upload-wrapper .onhow-studio-upload-text-input {
    display: block;
    width: 100%;
    padding: 0.625rem 0.75rem;
    font-size: 0.875rem;
    font-family: inherit;
    color: currentColor;
    background: transparent;
    border: 1.5px solid rgba(0, 0, 0, 0.2);
    border-radius: var(--onhow-studio-upload-radius);
    outline: none;
    box-sizing: border-box;
    transition: border-color 0.2s ease;
    -webkit-appearance: none;
    appearance: none;
  }

  .onhow-studio-upload-wrapper .onhow-studio-upload-text-input:focus {
    border-color: var(--onhow-studio-upload-primary);
  }

  .onhow-studio-upload-wrapper .onhow-studio-upload-text-input::placeholder {
    opacity: 0.4;
  }
</style>

<script>
  document.addEventListener('DOMContentLoaded', function () {
    (function() {
      var onhowStudioCredit = atob("RGVzaWduZWQgYnkgT05IT1cgU3R1ZGlvIC0gU3Vic2NyaWJlIQ==");
      console.log('%c ' + onhowStudioCredit, 'background: #222; color: #00ff00; padding: 4px; border-radius: 4px;');
    })();
    var config = document.getElementById('onhow-studio-upload-config');
    if (!config) return;

    var wrapper = document.querySelector('.onhow-studio-upload-wrapper');
    if (!wrapper) return;

    var productForm = document.querySelector('form[action*="/cart/add"]');
    if (!productForm) return;

    var mode        = config.dataset.mode;
    var accept      = config.dataset.accept;
    var label       = config.dataset.label;
    var maxSize     = parseInt(config.dataset.maxSize, 10);
    var btnText     = config.dataset.btnText;
    var helperText  = config.dataset.helperText;
    var errorType   = config.dataset.errorType;
    var errorSize   = config.dataset.errorSize;
    var textEnabled  = config.dataset.textInput === 'true';
    var textLabel    = config.dataset.textLabel;

    wrapper.style.setProperty('--onhow-studio-upload-primary', config.dataset.primary);
    wrapper.style.setProperty('--onhow-studio-upload-bg', config.dataset.bg);
    wrapper.style.setProperty('--onhow-studio-upload-radius', config.dataset.radius + 'px');
    wrapper.style.setProperty('--onhow-studio-upload-border-style', config.dataset.borderStyle);

    var labelEl   = wrapper.querySelector('.onhow-studio-upload-label');
    var zone      = wrapper.querySelector('.onhow-studio-upload-zone');
    var input     = wrapper.querySelector('.onhow-studio-upload-input');
    var hint      = wrapper.querySelector('.onhow-studio-upload-hint');
    var btn       = wrapper.querySelector('.onhow-studio-upload-btn');
    var preview   = wrapper.querySelector('.onhow-studio-upload-preview');
    var imgEl     = wrapper.querySelector('.onhow-studio-upload-img');
    var card      = wrapper.querySelector('.onhow-studio-upload-card');
    var cardName  = wrapper.querySelector('.onhow-studio-upload-card-name');
    var cardSize  = wrapper.querySelector('.onhow-studio-upload-card-size');
    var removeBtn = wrapper.querySelector('.onhow-studio-upload-remove');
    var errorEl   = wrapper.querySelector('.onhow-studio-upload-error');
    var textGroup = wrapper.querySelector('.onhow-studio-upload-text-group');
    var textLabelEl = wrapper.querySelector('.onhow-studio-upload-text-label');
    var textInput = wrapper.querySelector('.onhow-studio-upload-text-input');

    if (textEnabled) {
      textLabelEl.textContent  = textLabel;
      textInput.placeholder    = textLabel;
      textGroup.classList.remove('onhow-studio-upload-hidden');

      var hiddenText       = document.createElement('input');
      hiddenText.type      = 'text';
      hiddenText.id        = 'onhow-studio-upload-hidden-text';
      hiddenText.name      = 'properties[' + textLabel + ']';
      hiddenText.style.display = 'none';
      productForm.appendChild(hiddenText);

      textInput.addEventListener('input', function () {
        hiddenText.value = textInput.value;
      });
    }

    labelEl.textContent = label;
    hint.textContent    = helperText;
    btn.textContent     = btnText;

    input.setAttribute('name', 'properties[' + label + ']');
    input.setAttribute('accept', accept);

    if (mode === 'image') {
      card.classList.add('onhow-studio-upload-hidden');
    } else {
      imgEl.classList.add('onhow-studio-upload-hidden');
    }

    function formatSize(bytes) {
      if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
      return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
    }

    function showError(msg) {
      errorEl.textContent = msg;
      errorEl.classList.remove('onhow-studio-upload-hidden');
    }

    function clearError() {
      errorEl.textContent = '';
      errorEl.classList.add('onhow-studio-upload-hidden');
    }

    function clearPreview() {
      removeHiddenInput();
      preview.classList.add('onhow-studio-upload-hidden');
      zone.classList.remove('onhow-studio-upload-hidden');
      imgEl.src = '';
      cardName.textContent = '';
      cardSize.textContent = '';
      input.value = '';
    }

    function validateFile(file) {
      if (accept !== '*') {
        var types = accept.split(',').map(function (t) { return t.trim(); });
        var valid = types.some(function (t) {
          if (t.slice(-2) === '/*') return file.type.startsWith(t.slice(0, -2));
          return file.type === t;
        });
        if (!valid) { showError(errorType); return false; }
      }
      if (file.size > maxSize * 1024 * 1024) { showError(errorSize); return false; }
      return true;
    }

    function injectHiddenInput(file) {
      var existing = productForm.querySelector('#onhow-studio-upload-hidden');
      if (existing) existing.remove();
      var hidden = document.createElement('input');
      hidden.type = 'file';
      hidden.id   = 'onhow-studio-upload-hidden';
      hidden.name = 'properties[' + label + ']';
      hidden.style.display = 'none';
      var dt = new DataTransfer();
      dt.items.add(file);
      hidden.files = dt.files;
      productForm.appendChild(hidden);
    }

    function removeHiddenInput() {
      var existing = productForm.querySelector('#onhow-studio-upload-hidden');
      if (existing) existing.remove();
    }

    function handleFile(file) {
      clearError();
      if (!validateFile(file)) { clearPreview(); return; }

      injectHiddenInput(file);

      if (mode === 'image') {
        var reader = new FileReader();
        reader.onload = function (e) {
          imgEl.src = e.target.result;
          zone.classList.add('onhow-studio-upload-hidden');
          preview.classList.remove('onhow-studio-upload-hidden');
        };
        reader.readAsDataURL(file);
      } else {
        cardName.textContent = file.name;
        cardSize.textContent = formatSize(file.size);
        zone.classList.add('onhow-studio-upload-hidden');
        preview.classList.remove('onhow-studio-upload-hidden');
      }
    }

    input.addEventListener('change', function () {
      if (this.files[0]) handleFile(this.files[0]);
    });

    removeBtn.addEventListener('click', clearPreview);

    zone.addEventListener('click', function () {
      input.click();
    });

    btn.addEventListener('click', function (e) {
      e.stopPropagation();
      input.click();
    });

    zone.addEventListener('dragover', function (e) {
      e.preventDefault();
      zone.classList.add('onhow-studio-upload-drag-over');
    });

    zone.addEventListener('dragleave', function () {
      zone.classList.remove('onhow-studio-upload-drag-over');
    });

    zone.addEventListener('drop', function (e) {
      e.preventDefault();
      zone.classList.remove('onhow-studio-upload-drag-over');
      var file = e.dataTransfer.files[0];
      if (!file) return;
      var dt = new DataTransfer();
      dt.items.add(file);
      input.files = dt.files;
      handleFile(file);
    });
  });
</script>

{% comment %}
<!-- Designed by ONHOW Studio - Anas El Medlaoui -->
{% endcomment %}