- Step 1 – Open the right file in your theme.
- Step 2 – Give the note field an ID (if it doesn’t have one)
- Step 3 – Add an error message container
- Step 4 – Add the validation script in the same section
- Step 5 – Test in the theme editor
- If you’re using the cart drawer too
- Update to Only Force the Note for Zero Dollar Items
- 1️⃣ Add a “has free item” flag in main-cart-footer.liquid
- 2️⃣ Keep the note + error message as before
- 3️⃣ Replace the old script with this one
- What this does now
- 4️⃣ Quick test checklist
- Item that are Zero vs Total line being Zero
Often with store pickup or local delivery customers need to add notes but forget.
Step 1 – Open the right file in your theme. #
- In Shopify admin go to Online Store → Themes.
- On your “Latest” / Current theme, click … → Edit code.
- 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 #
- In Online Store → Themes, click Customize on your current theme.
- Use the top dropdown to go to the Cart page.
- 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.liquidaround 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 == 0checks 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:
- No free items in cart → leave note blank → click Checkout → you should go through.
- Add a free item (or discount to 100% off) → leave note blank → click Checkout → you should see the error and stay on the cart.
- 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 == 0→ per-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.


