One of the key advantages of React Hook Form is its reliance on uncontrolled components, which improves performance by reducing unnecessary re-renders. However, this can make it less obvious how to manipulate or transform user input in real-time—for example, limiting numbers to a maximum of 100, or automatically converting input text to uppercase.
At first, I was confused about how to implement these kinds of input transformations with React Hook Form. Most answers I found only pointed to validation (e.g., setting max: 100 in the validation schema), which is useful for preventing form submission—but it doesn’t stop the user from entering invalid input in the first place.
In contrast, with Formik, it was straightforward to customize input behavior using the handleChange function. I wondered whether React Hook Form provided a similar mechanism. Fortunately, it does—via the Controller component.
The Controller component gives you access to the onChange handler and the value, which lets you intercept and modify user input before it’s registered in the form state. This makes it easy to implement input restrictions or transformations directly:
<Controller
name={`rows.${index}.${rawKey}.${cell.column.id}`}
control={nutControl}
defaultValue={value}
rules={{ min: 0, max: 100 }} //Validation
render={({ field }) => (
<input
type="number"
inputMode="numeric"
dir="ltr"
className="text-center w-[60px] hover:cursor-
pointer inline-block border border-transparent
hover:border-gray-300 rounded"
{...field}
value={field.value ?? ''}
onChange={(e) => {
const num = Number(e.target.value)
if (Number.isNaN(num) || num < 0 || num > 100) return
field.onChange(num)
}}
/>
)}