In Formik 2, how do you build a reusable custom input with useField, and what do the three values it returns hold?
answer
- a hook for field components
- props, status, setters
- events versus plain values
- needs Formik's context
basics
~20 sIn Formik 2, useField(name) returns [field, meta, helpers]: field holds name, value, onChange and onBlur to spread onto an input; meta holds value, error, touched and initial values; helpers holds setValue, setTouched and setError for non-event widgets.
solid answer
~40 s`useField` is the hook form of `<Field>`. Called inside a `<Formik>` tree as `useField('email')` or `useField({ name, type, validate })`, it returns a tuple. **`field`** — `{ name, value, onChange, onBlur }` plus `checked`/`multiple` for checkboxes and selects — is what you spread onto a native input. **`meta`** — `{ value, error, touched, initialValue, initialTouched, initialError }` — drives the label, the error and styling, typically `meta.touched && meta.error`. **`helpers`** — `{ setValue, setTouched, setError }` — is for widgets that report a plain value rather than a DOM event, such as a date picker's `onChange(date)`: call `helpers.setValue(date)` and `helpers.setTouched(true)`. Passing a `validate` function registers a field-level validator. Because it reads context, `useField` does not work in a form built only with `useFormik()`.
code
tsx · 17 linesimport { useField } from 'formik';
import { DatePicker } from './DatePicker'; // a controlled widget: value, onChange(Date | null), onClose
export function DateField({ name, label }: { name: string; label: string }) {
const [field, meta, helpers] = useField<Date | null>(name);
return (
<div>
<span>{label}</span>
<DatePicker
value={field.value}
onChange={(date) => helpers.setValue(date)}
onClose={() => helpers.setTouched(true)}
/>
{meta.touched && meta.error ? <p role="alert">{meta.error}</p> : null}
</div>
);
}go deeper
Recall the tuple order, field then meta then helpers, and spread field onto a native input.
Explain why value-reporting widgets use helpers.setValue and setTouched instead of field.onChange.
Build a small field kit on useField with consistent error display, touched handling and field-level validators.
Decide how a design system's inputs integrate with the form library so screens never hand-wire events.
## Why useField exists `<Field>` is convenient for native inputs, but a design system needs its own components: a text input with a label and error text, a masked phone field, a date picker. `useField` gives such a component everything `<Field>` would inject, as a hook, so the component decides its own markup. ## The three return values `const [field, meta, helpers] = useField(nameOrOptions)`: | Value | Members | Use it for | |---|---|---| | `field` | `name`, `value`, `onChange`, `onBlur`, and `checked` / `multiple` where relevant | Spreading onto a native `<input>`, `<select>` or `<textarea>` | | `meta` | `value`, `error`, `touched`, `initialValue`, `initialTouched`, `initialError` | Showing the error, styling invalid state, comparing with the initial value | | `helpers` | `setValue(value, shouldValidate?)`, `setTouched(value, shouldValidate?)`, `setError(value)` | Widgets whose change callback gives a value, not an event | The argument is either the field name or an options object — `{ name, type, validate, multiple, value }`. Passing `type: 'checkbox'` makes `field.checked` meaningful; passing `validate` registers a **field-level validator** that Formik merges with form-level validation. ## Building a labelled text input 1. Accept `label` and the input props, including `name`. 2. Call `useField(props)`. 3. Spread `field` and the remaining props onto the `<input>`. 4. Render `meta.error` when `meta.touched` is true. ```tsx function TextInput({ label, ...props }: { label: string; name: string; type?: string }) { const [field, meta] = useField(props); return ( <label> {label} <input {...field} {...props} aria-invalid={meta.touched && !!meta.error} /> {meta.touched && meta.error ? <span>{meta.error}</span> : null} </label> ); } ``` ## Widgets that report a value, not an event `field.onChange` is Formik's `handleChange`. It expects a change event; called with a string, it treats the string as a field path and returns a new handler instead. A date picker calling `onChange(new Date(...))` fits neither shape, so do not pass `field.onChange` straight through. Instead: - call `helpers.setValue(date)` from the widget's change callback; - call `helpers.setTouched(true)` from its blur or close callback, so the touched gate opens; - read the current value from `field.value` (or `meta.value`). `setValue` and `setTouched` validate according to `validateOnChange` and `validateOnBlur`, and both accept a `shouldValidate` argument to override that per call. ## Where it can be called `useField` reads Formik's **context**, so it works anywhere under `<Formik>` or `withFormik` — however deep — and not in a form built only with `useFormik()`. Field components built on it can be reused across every Formik form in an app without prop drilling. ## Pitfalls - **Stale closures around `helpers`.** The documentation's type makes `setValue` return a promise; do not assume the new value is in `meta.value` on the same line. - **Forgetting touched for custom widgets.** Without `setTouched`, the error stays hidden until submit touches every field. - **Reusing a name.** Two components with the same `name` share one value, which is usually a bug. - **Rendering cost.** A component using `useField` re-renders with the form, like `<Field>`; for large forms see `<FastField>`.
- In Formik 2, what is the difference between useField and useFormikContext for a custom input?`useField(name)` is scoped to one field: it hands back that field's props, meta and helpers. `useFormikContext()` returns the whole form bag — all `values`, `errors`, `setFieldValue` — which suits components that span fields, such as a summary or a submit button. For a single input, `useField` is less code and clearer.
- How do you attach a validator to one field through useField in Formik 2?Pass an options object: `useField({ name: 'username', validate: checkUsername })`. Formik registers the function as a field-level validator and runs it with form-level `validate` and `validationSchema`, deeply merging the results. It may return a message string or a promise of one.
saying these in an interview costs you the question
- useField returns [value, setValue], like useState
- field.onChange accepts any value, so pass it straight to a date picker
- useField works in any component, even outside a Formik form
- meta.error is only set after the form has been submitted
- A custom widget does not need to report blur