· 6 min read
Empty is not zero: designing number inputs for money
Why a blank cash field and a 0 mean different things in a POS, and the small input rules that keep a cash count honest.
A blank field and a 0 look almost the same on screen, but in a money input they mean different things: empty means nobody entered a value, and zero means someone checked and the answer was nothing. If a form quietly turns blank into 0, a forgotten cash count becomes an honest-looking empty drawer, and every total after it is wrong. Good number input UX keeps the two apart: accept a typed 0 where zero is a real answer, reject a blank, and reject 0 where it describes an event that cannot be zero.
I learned to care about this while designing cash sessions for Tigg POS, the point-of-sale product I work on at BIC Technology. The full story is in the cash sessions case. This post pulls out the input rules, because they apply to any form that records money, stock or counts.
Why a blank field is not zero
In a cash count, there are two different situations that a careless input treats as one.
- Blank: the cashier forgot to enter the opening count, or skipped it. The value is unknown.
- Zero: the cashier opened the drawer, looked, and it was empty. The value is known, and it is nothing.
When I worked out what each one meant for the shop, the answer was simple: empty means they forgot to input; zero means there is no cash. Those lead to different actions. A forgotten count needs someone to go back and count. A zero count is a fact the rest of the session can be checked against.
Many form libraries and spreadsheet habits blur this. An empty number field is read as 0 "for convenience", or a sum treats missing cells as 0. In a report that might not matter. In a cash drawer it matters a lot, because the expected cash for the session is built on the opening count:
Expected cash = opening count + cash sales − cash refunds + credit collected in cash + cash in − cash out
If the opening count is silently 0 when it was really Rs 5,000, the drawer will appear Rs 5,000 over at close. Nobody did anything wrong at the counter. The interface invented a fact.
Balances and events need different rules
The second thing I had to work out was that not every money field should treat zero the same way. A balance describes how much there is at a moment. An event describes something that happened. A balance of zero is normal. An event of zero didn't happen.
| Field | What it records | Blank | 0 | Message on reject |
|---|---|---|---|---|
| Opening count | A balance | Rejected | Accepted, and stays visible | "Enter an opening amount." |
| Closing count | A balance | Rejected | Accepted | "Enter a counted amount." |
| Cash in | An event | Rejected | Rejected | "Enter an amount greater than zero." |
| Cash out | An event | Rejected | Rejected | "Enter an amount greater than zero." |
One case surprised me. When a cashier counts by denomination, with a row for each note from Rs 1,000 down to Rs 1, every row can be at 0. For an opening count that is a valid balance: the drawer is empty. For a cash movement it is not valid, because the sum is zero and a movement of nothing is not a movement. The same input, two different rules, depending on what the field means.
How to design a number input for money
These are the rules I now apply to any field that records money or a count.
Keep a typed 0 visible
If someone types 0, show 0. Don't clear it on blur, don't replace it with a placeholder, and don't format it away. The person needs to see what they confirmed. A field that looks empty after you typed 0 makes people type it again, or doubt that it saved.
Never turn blank into 0 on save
Validation should see the difference between "no value" and "the value zero". If the field is required, a blank should block with a message that says what to do. If the field is optional, blank should be stored as "not entered", not as 0.
Reject zero only where zero is impossible
Ask whether the field is a balance or an event. Balances accept zero. Events, such as a payment, a transfer or a cash movement, need an amount greater than zero.
Write the message as an instruction
"Enter an opening amount." tells the cashier what to do next. "Invalid value" doesn't. Short, specific, and on the field itself.
Treat defaults as claims
A pre-filled number is more dangerous than an empty field, because it passes validation. I learned this on a different feature. In Tigg's multi-currency forms, an exchange rate of 1 is correct for NPR, but if someone switched the currency to USD the 1 stayed, and saving worked. The fix was to clear the rate and make it required whenever the form leaves NPR. The details are in the currency case.
Let a cleared field stay cleared
The same idea applies to dates. In Tigg's company-creation flow, clearing a Bikram Sambat date and pressing Tab used to fill a default date back in, which looks like the person's own input. The fix was to let a cleared field stay empty so the "required" message could do its job. It is in the admin and ERP case.
Empty vs zero: a checklist for form validation
Before I call a money form done, I check each field against these questions:
- Does the field record a balance or an event?
- What does blank mean here: unknown, not applicable, or skipped on purpose?
- Is 0 a real answer? If yes, is it accepted and still visible after saving?
- Does the save path ever turn blank into 0, or a missing value into a default?
- Is any value pre-filled? Is that value true in every context the form can reach?
- Does each rejection say what to do, in words, on the field?
- When a total is computed, are unknown parts shown as unknown, not as zero?
The last question matters most for screens that summarise. In cash sessions, a session that was started without an opening count does not show an opening of Rs 0. At a location that verifies cash, the drawer card says the opening balance still needs to be entered, with a button to enter it. An unknown part of a sum should look unknown.
What the rule costs
Strict input rules cost a little speed. A cashier with a really empty drawer has to type 0 instead of pressing Start with the field blank. I think that is the right trade: one keystroke turns an assumption into a record. It is also why the strict rules apply only at locations that switch on cash verification. Shops that don't want counts can start and close sessions in one click each, and add counts later if they want.
I should be clear about the evidence. These rules came from reasoning about what each number means, an internal walkthrough with real cash drawers, and QA's testing. They were not tested with cashiers before release, and no outcome has been measured since. The CEO has reported to me that the feature is live and properly used by real shops. If I could measure one thing here, it would be how often a verified session closes with a count at all.
The rule is small enough to carry anywhere: in anything financial, nothing should never have two meanings. For more states like this one, see the state checklist for business software. For the decision that sits next to it in the closing flow, read blind counts and anchoring.
questions people ask
Frequently asked questions
What is the difference between an empty field and zero in a form?
An empty field means the value is unknown: nobody entered it. Zero is a known value: someone checked and the answer was nothing. In money forms the two must never be treated as the same thing.
Should a number input convert a blank value to 0?
Not for anything that records a fact, such as a cash count. Converting blank to 0 makes a forgotten entry look like a real, confirmed zero, and every calculation that depends on it becomes wrong without any visible error.
When should zero be rejected in a money input?
When the field records an event rather than a balance. A cash-in or cash-out of Rs 0 did not happen, so it should require an amount greater than zero. A balance of Rs 0, such as an empty drawer, is a valid answer.
Is a pre-filled default safer than an empty field?
Often it is less safe. A pre-filled number passes validation, so a wrong default is never caught. An empty, required field makes someone give the real value.