If you’ve spent any time building forms in React Native with React Hook Form and validation libraries like Zod or Yup, you’ve likely encountered a strange phenomenon: the "Disappearing Zero."
One minute you're building a sleek checkout or progress flow, and the next, your users are complaining that every time they try to enter 0
, the input field just... wipes itself clean.
The culprit? JavaScript’s definition of "falsy."
The Trap: JavaScript Falsiness #
In React Native, numeric inputs often start as null
or undefined
(or a number type in your state). Since TextInput
(or custom Input components) expect a string
, a common pattern is to cast the value like this:
// ❌ The Buggy Way
value={value ? String(value) : ''}
On the surface, this looks clean. If there's a value, stringify it; otherwise, show an empty string.
The Gotcha: In JavaScript, 0
is falsy.
When a user types "0", the expression value ? ...
evaluates to false
, and the input receives an empty string (''
). The zero vanishes instantly, leaving your users confused and your validation library potentially complaining about a missing value.
The Solution: Explicit Checks #
To fix this, we need to stop relying on loose truthiness and start checking for what we actually care about: whether the value is null or undefined.
// ✅ The Robust Way
value={value !== null && value !== undefined ? String(value) : ''}
By being explicit, we ensure that 0
(which is not null or undefined) is correctly stringified and rendered in the UI.
Real-World Example: React Hook Form + Controller #
Here is how this looks in a typical implementation. In this example, we're tracking "Completed Stages," where 0
is a perfectly valid (and common) input.
<Controller
control={control}
name="completedStages"
render={({ field: { onChange, onBlur, value } }) => (
<Input
label="Completed Stages"
// The Fix: Ensure 0 is correctly rendered as a string
value={value !== null && value !== undefined ? String(value) : ''}
onChangeText={(text) => {
// Convert back to number for your validation schema (Zod/Yup)
const parsed = parseInt(text, 10);
onChange(isNaN(parsed) ? undefined : parsed);
}}
onBlur={onBlur}
keyboardType="number-pad"
placeholder="5"
error={errors.completedStages?.message}
/>
)}
/>
Why This Matters for Zod and Yup #
Validation libraries like Zod and Yup are strict about types. If your UI logic converts a 0
into an empty string (''
), your schema validation might fail with a "Required" error or a type mismatch, even though the user intended to enter zero.
By fixing the UI representation, you keep your data flow consistent:
User enters 0-> UI sees "0". -
onChange parses "0"-> Hook Form stores0
. -
Zod/Yup validates-> Success!0
Summary #
In React Native forms, truthiness is often too blunt a tool for numeric inputs. When handling the value
prop:
-
Avoid
value ? String(value) : '' -
Prefer
value !== null && value !== undefined ? String(value) : ''
It’s a tiny change that prevents one of the most common (and annoying) bugs in mobile form development.