Fix Form Comparisons That Confuse Blank Input With Zero
Separate missing, invalid and numeric form input, then compare normalized quantities without treating an empty field as zero.
A form field containing zero and an empty form field need different handling. A coercing comparison can treat both as zero, while comparing the raw input directly with a numeric zero using strict equality misses the valid zero too. Fix the boundary where text becomes application data.
This guide uses one local form to distinguish missing input, a valid zero and an invalid quantity. The course comparison lesson covers the broader operator rules. Here the outcome is a form whose messages follow an explicit input contract.
Reproduce the empty-field mistake
Save this complete example as label-quantity.html and open it in a current browser. It processes sample data locally and prevents form submission, so nothing is sent to a server.
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Blank quantity or zero?</title>
<style>
body { font: 1rem/1.5 system-ui; max-width: 40rem; margin: 2rem auto; padding: 0 1rem; }
label, input, output { display: block; }
input { box-sizing: border-box; width: 100%; font: inherit; padding: .5rem; }
button { font: inherit; padding: .5rem; margin-top: .75rem; }
output { margin-top: 1rem; }
pre { white-space: pre-wrap; overflow-wrap: anywhere; }
</style>
<h1>Prepare sample labels</h1>
<form id="label-form" novalidate>
<label for="quantity">Quantity, from 0 to 99</label>
<input id="quantity" type="text" inputmode="numeric" autocomplete="off" aria-describedby="help">
<p id="help">Enter 0 for no labels. A blank field is missing information.</p>
<button type="submit">Check quantity</button>
</form>
<output id="result" aria-live="polite"></output>
<pre id="trace"></pre>
<script>
const form = document.querySelector("#label-form");
const field = document.querySelector("#quantity");
const result = document.querySelector("#result");
const trace = document.querySelector("#trace");
form.addEventListener("submit", event => {
event.preventDefault();
const raw = field.value;
trace.textContent = `value=${JSON.stringify(raw)}, type=${typeof raw}`;
result.textContent = raw == 0 ? "Zero: no labels requested." : `Queue ${raw} labels.`;
});
</script>
</html>
Submit the empty field, then spaces, then 0. All three produce the same zero message. The trace shows a string in every case, even when the input looks numeric. inputmode="numeric" suggests a keyboard; it does not convert the value or validate it.
Define what this quantity means
The contract is a whole-number count from 0 to 99. Surrounding whitespace is allowed and trimmed. Blank input is missing. Signs, decimal fractions, exponents and leading zeros such as 05 are rejected. These are decisions for this form, not universal rules for numeric input.
Do not apply the same conversion to an identifier such as a product code or postal code: leading zeros may be meaningful there. First decide whether the value represents a number or a text identifier.
Normalize once, then compare numbers
Replace the original submit listener with the entire block below, including the helper. Keep the existing element lookups. This checks missing input before conversion, validates the agreed syntax, and produces a number only for an accepted value.
function readQuantity(raw) {
const text = raw.trim();
if (text === "") {
return { ok: false, message: "Enter a quantity." };
}
if (!/^(0|[1-9][0-9]?)$/.test(text)) {
return { ok: false, message: "Use a whole number from 0 to 99." };
}
return { ok: true, value: Number(text) };
}
form.addEventListener("submit", event => {
event.preventDefault();
const raw = field.value;
const parsed = readQuantity(raw);
trace.textContent = `value=${JSON.stringify(raw)}, type=${typeof raw}`;
field.setAttribute("aria-invalid", String(!parsed.ok));
if (!parsed.ok) {
result.textContent = parsed.message;
return;
}
const quantity = parsed.value;
result.textContent = quantity === 0
? "Zero: no labels requested."
: `Queue ${quantity} ${quantity === 1 ? "label" : "labels"}.`;
});
The early empty-string check gives a specific missing-value message. The pattern restricts the allowed syntax and range. Only then does Number convert the text; the final quantity === 0 compares two numbers. The original field is left intact so a person can correct what they typed.
Changing only raw == 0 to raw === 0 is incomplete: the field's "0" is still a string, so the numeric comparison fails. Converting immediately without checking missing input is also incomplete: Number("") and Number(" ") both produce zero.
Test all three input states
Reload after saving. Run this sequence in the same page and check both the message and aria-invalid. Missing or invalid input should be marked invalid; valid zero and positive counts should clear that state.
| Input | Expected result |
|---|---|
| Blank or spaces | Enter a quantity. |
| 0 | Zero: no labels requested. |
| 1 | Queue 1 label. |
| 12, including surrounding spaces | Queue 12 labels. |
| 99 | Queue 99 labels. |
| 100, -1, 1.5 or abc | Use a whole number from 0 to 99. |
| 05 or 1e1 | Rejected by this form's syntax rule |
Use Enter as well as the button. Focus should stay usable and the live output should announce the result. Clear a previously valid value and submit again: it must return to the missing-input message rather than retain the earlier result.
Keep conversion failures visible
- Zero is still treated as missing: look for a truthiness check such as
if (!quantity). Zero is falsy, but valid here. - abc reaches the queue message: confirm the validation return runs before the comparison and rendering.
- The browser rewrites invalid text: this example intentionally uses a text field so its accepted syntax is visible. A number field has different browser validation and
valueAsNumberbehavior. - The page reloads on Enter: make sure the submit listener is attached to the form and calls
preventDefault().
Try removing the input contract
Suppose the handler becomes only Number(field.value) === 0. Which missing values would now reach the zero branch, and would it reject scientific notation?
Answer: blank and whitespace-only strings become zero. Scientific notation such as 1e1 converts to 10 rather than being rejected. Explicit conversion is necessary here, but it does not replace the missing-value and syntax decisions.
References: input values are strings and Number conversion behavior.
About
Separate missing, invalid and numeric form input, then compare normalized quantities without treating an empty field as zero.
- Responsible
- Mary Q
- Last Update
- 09/01/2026
- Reading Time
- 6 min
Reviews
Sign in to write a reviewComments (0)
Sign in to commentNo comments yet.