View Categories

Making Your Notes Field Required in Shopify

7 min read

Often with store pickup or local delivery customers need to add notes but forget.

Step 1 – Open the right file in your theme. #

  1. In Shopify admin go to Online Store → Themes.
  2. On your “Latest” / Current theme, click … → Edit code.
  3. In the left sidebar, under Sections, open:

main-cart-footer.liquid
or, if you don’t see that, open main-cart-items.liquid.

Dawn v15+ usually puts the cart note in main-cart-footer.liquid.


Step 2 – Give the note field an ID (if it doesn’t have one) #

Inside main-cart-footer.liquid, look for something like this:

<textarea   name="note"   ... >   {{ cart.note }} </textarea>

Change it to:

<textarea   id="CartSpecialInstructions"   name="note"   {{ block.shopify_attributes }} >   {{ cart.note }} </textarea>

If there’s already an id (like Cart-note), you can keep it, just remember what it is and use that in the script.


Step 3 – Add an error message container #

Right under that <textarea>, add:

<div id="CartNoteError"      style="display:none; color:red; font-size:0.9rem; margin-top:0.25rem;">   Please enter a note before continuing to checkout. </div>

You can style that with theme classes later; this just makes it work.


Step 4 – Add the validation script in the same section #

Scroll to the bottom of main-cart-footer.liquid, and just before the closing {% schema %} (or at the bottom if there’s no schema), paste this:

<!--RP Tech Support - Added Required Fields -->
<script>
document.addEventListener('DOMContentLoaded', function () {
var noteField = document.getElementById('Cart-note');
var errorEl = document.getElementById('CartNoteError');

if (!noteField || !errorEl) return;

function showError(message) {
errorEl.textContent = message;
errorEl.style.display = 'block';
}

function hideError() {
errorEl.style.display = 'none';
}

var checkoutButtons = document.querySelectorAll(
'button[name="checkout"], button[id="checkout"], button[type="submit"][name="checkout"]'
);

checkoutButtons.forEach(function (btn) {
// NOTE: third argument "true" = capture phase
btn.addEventListener('click', function (event) {
var value = noteField.value.trim();

if (!value) {
// Block default form submit
event.preventDefault();
// Block any other click handlers on this button
event.stopImmediatePropagation();

showError('Please enter a note before continuing to checkout.');
noteField.focus();
} else {
hideError();
// If valid, do NOT preventDefault — default submit + other JS still run
}
}, true);
});

noteField.addEventListener('input', function () {
if (noteField.value.trim()) {
hideError();
}
});
});
</script>

That will:

  • Block checkout when the cart note is empty.
  • Show a red message under the note.
  • Clear the message as soon as the customer starts typing.

Step 5 – Test in the theme editor #

  1. In Online Store → Themes, click Customize on your current theme.
  2. Use the top dropdown to go to the Cart page.
  3. Try:
    • Leaving the note blank → click Checkout → you should see the error and stay on the cart.
    • Typing something → click Checkout → you should go to Shopify Checkout.

If you’re using the cart drawer too #

The above only enforces it on the cart page. If your theme uses the cart drawer, and you want to force notes there too, you’ll need a similar script in cart-drawer.liquid targeting that drawer’s textarea and checkout button.

If you paste:

  • A small snippet of your main-cart-footer.liquid around the note field, or
  • A screenshot of your cart section in the theme editor,

Update to Only Force the Note for Zero Dollar Items #

Here is a Nice tweak 👌 — we’ll only force the note if any cart line is free (0.00).

We’ll use Liquid to detect free items, then JS to enforce the note only in that case.


1️⃣ Add a “has free item” flag in main-cart-footer.liquid #

In Edit code → Sections → main-cart-footer.liquid, somewhere above your <textarea> or above the script, add this Liquid snippet:

{%- assign has_free_item = false -%} {%- for item in cart.items -%}   {%- if item.final_line_price == 0 -%}     {%- assign has_free_item = true -%}   {%- endif -%} {%- endfor -%}  <div   id="CartHasFreeItem"   data-has-free-item="{{ has_free_item }}"   style="display:none;" ></div>
  • item.final_line_price == 0 checks for any line whose total is 0 (e.g. freebies, 100% discounts).
  • We store that as data-has-free-item="true" or "false".

Leave that div hidden; it’s just for JS.


2️⃣ Keep the note + error message as before #

Make sure your note textarea and error container look like this (or similar):

<textarea   id="CartSpecialInstructions"   name="note"   {{ block.shopify_attributes }} >   {{ cart.note }} </textarea>  <div id="CartNoteError"      style="display:none; color:red; font-size:0.9rem; margin-top:0.25rem;">   Please enter a note before continuing to checkout. </div>

(If you already added this from the previous step, you’re good.)


3️⃣ Replace the old script with this one #

Still in main-cart-footer.liquid, at the bottom of the file (before {% schema %}), remove the previous script I gave you and paste this updated version:

<script>
document.addEventListener('DOMContentLoaded', function () {
var noteField = document.getElementById('Cart-note');
var errorEl = document.getElementById('CartNoteError');

if (!noteField || !errorEl) return;

function showError(message) {
errorEl.textContent = message;
errorEl.style.display = 'block';
}

function hideError() {
errorEl.style.display = 'none';
}

var checkoutButtons = document.querySelectorAll(
'button[name="checkout"], button[id="checkout"], button[type="submit"][name="checkout"]'
);

checkoutButtons.forEach(function (btn) {
// NOTE: third argument "true" = capture phase
btn.addEventListener('click', function (event) {
var flagEl = document.getElementById('CartHasFreeItem');
var hasFreeItem =
flagEl && flagEl.dataset.hasFreeItem === 'true';

// If no free items, don't enforce; let other JS do its thing
if (!hasFreeItem) {
hideError();
return;
}

var value = noteField.value.trim();

if (!value) {
// Block default form submit
event.preventDefault();
// Block any other click handlers on this button
event.stopImmediatePropagation();

showError('Please enter a note before continuing to checkout.');
noteField.focus();
} else {
hideError();
// If valid, do NOT preventDefault — default submit + other JS still run
}
}, true);
});

noteField.addEventListener('input', function () {
if (noteField.value.trim()) {
hideError();
}
});
});
</script>

What this does now #

  • If no line item is free (0.00) → checkout works normally, even with an empty note.
  • If at least one line item is free → note becomes required; empty note blocks checkout and shows the red message.

4️⃣ Quick test checklist #

On the cart page:

  1. No free items in cart → leave note blank → click Checkout → you should go through.
  2. Add a free item (or discount to 100% off) → leave note blank → click Checkout → you should see the error and stay on the cart.
  3. With free item in cart, fill in note → click Checkout → should go through.

Item that are Zero vs Total line being Zero #

If you want it to be “price 0 per unit” instead of “line total 0”, here is the tweak the Liquid to check item.final_price instead of item.final_line_price.

You only need to change the Liquid flag block; the JS stays the same.


1️⃣ Update the “has free item” flag to use unit price #

In main-cart-footer.liquid, replace the previous flag block with this:

{%- assign has_free_item = false -%} {%- for item in cart.items -%}   {%- if item.final_price == 0 -%}     {%- assign has_free_item = true -%}   {%- endif -%} {%- endfor -%}  <div   id="CartHasFreeItem"   data-has-free-item="{{ has_free_item }}"   style="display:none;" ></div>
  • Now it checks item.final_price == 0per-unit final price is free, even if quantity > 1.

Leave your textarea, error div, and script exactly as they were from the last step:

<textarea   id="CartSpecialInstructions"   name="note"   {{ block.shopify_attributes }} >   {{ cart.note }} </textarea>  <div id="CartNoteError"      style="display:none; color:red; font-size:0.9rem; margin-top:0.25rem;">   Please enter a note before continuing to checkout. </div>

And the script:

<script>   document.addEventListener('DOMContentLoaded', function () {     var noteField = document.getElementById('CartSpecialInstructions');     var errorEl   = document.getElementById('CartNoteError');      if (!noteField || !errorEl) return;      var checkoutButtons = document.querySelectorAll(       'button[name="checkout"], button[id="checkout"], button[type="submit"][name="checkout"]'     );      function showError(message) {       errorEl.textContent = message;       errorEl.style.display = 'block';     }      function hideError() {       errorEl.style.display = 'none';     }      checkoutButtons.forEach(function (btn) {       btn.addEventListener('click', function (event) {         var flagEl = document.getElementById('CartHasFreeItem');         var hasFreeItem =           flagEl && flagEl.dataset.hasFreeItem === 'true';          // If there are no free items by unit price, don't enforce the note         if (!hasFreeItem) {           return;         }          var value = noteField.value.trim();          if (!value) {           event.preventDefault();           showError('Please enter a note before continuing to checkout.');           noteField.focus();         } else {           hideError();         }       });     });      // Clear error while typing     noteField.addEventListener('input', function () {       if (noteField.value.trim()) {         hideError();       }     });   }); </script>

2️⃣ Quick sanity check #

  • Item at $0.00 per unit (no matter the quantity) → note required.
  • Discounted to $0.00 per unit via automatic discount/code → note required.
  • All items have unit price > 0 → note optional.