Shipmind Labs

A tester filed a bug against our amount field that read, roughly: the field argues back while the number is still being typed.

The repro set a minimum of 50. Type "100" and the field goes red at "1", red at "10", and calm at "100". Technically correct on every keystroke. Unusable.

What we had gotten wrong was treating both bounds as the same kind of fact.

Above the maximum is final. If the number is already too big, more digits only make it bigger, and no continuation of that input rescues it. Below the minimum is a maybe. "1" is on its way to "100".

So in amountfield, our open-source money input, the two bounds now report on different clocks.

While typing: above-maximum becomes a problem immediately, and the field stops calling itself incomplete. Below-minimum is swallowed, no problem reported, and the field marks itself incomplete, which is the honest description of a half-entered number.

On blur: the problem is recomputed from the settled value and incomplete goes false. The minimum gets reported once the value has stopped moving.

On first render of a prefilled value: either bound reports at once, because nothing is in flight.

One thing does not wait for any of that. Before anything is compared, each bound is checked against the field's currency and exponent, and a mismatch throws (wrong currency code, wrong exponent). That check runs first on all three paths, so a bound configured in the wrong currency fails on an empty field, before anyone has typed a character. A wrong bound is our bug, not the user's, and it should not hide until someone fills the form.

The comparison itself is deliberately boring: counts of minor units, nothing else, and a bound exactly equal to the amount sits inside.

The accessibility layer follows the same split. The invalid state is bound to whether a problem exists, so a screen reader is not told the number is wrong while it is still being typed.

The rule we took away, and now apply to every form field we build: before deciding when to surface a validation error, ask whether more input can still fix it. If yes, wait for blur. If no, say it now.

We are curious how you model the half-typed state in your own forms, as incomplete, or just as not-yet-invalid.

Was this useful?

Building something similar?

or email hello@shipmindlabs.com