useField
The
useField
function is part of Conform's future export. These APIs are experimental and may change in minor versions. Learn more
A React hook that provides access to a specific field's metadata and state from any component within a FormProvider
context.
import { useField } from '@conform-to/react/future';
const field = useField(name, options);
#Parameters
name: FieldName<FieldShape>
The name of the input field.
options.formId?: string
Optional form identifier to target a specific form when multiple forms are rendered. If not provided, uses the nearest form context.
#Returns
A Field
object containing field metadata and state:
id: string
The field's unique identifier, automatically generated as {formId}-{fieldName}
.
name: FieldName<FieldShape>
The field name path exactly as provided. The FieldName type is just a branded string type to help with TypeScript inference.
descriptionId: string
Auto-generated ID for associating field descriptions via aria-describedby
.
errorId: string
Auto-generated ID for associating field errors via aria-describedby
.
defaultValue: string | undefined
The field's default value as a string.
defaultOptions: string[] | undefined
Default selected options for multi-select fields or checkbox group.
defaultChecked: boolean | undefined
Default checked state for checkbox/radio inputs.
touched: boolean
Whether this field has been touched (through intent.validate()
or the shouldValidate
option).
invalid: boolean
Whether this field currently has validation errors.
errors: ErrorShape[] | undefined
Array of validation error messages for this field.
Validation Attributes
HTML validation attributes automatically derived from schema constraints:
required?: boolean
minLength?: number
maxLength?: number
pattern?: string
min?: string | number
max?: string | number
step?: string | number
multiple?: boolean
getFieldset(): Fieldset<FieldShape>
Method to get nested fieldset for object fields under this field.
getFieldList(): Field[]
Method to get array of fields for list/array fields under this field.
#Example
Dynamic field components
1import { useField } from '@conform-to/react/future';
2
3interface FieldProps {
4 name: string;
5 label: string;
6 type?: string;
7}
8
9function FormField({ name, label, type = 'text' }: FieldProps) {
10 const field = useField(name);
11
12 return (
13 <div className={`form-field ${field.invalid ? 'invalid' : ''}`}>
14 <label htmlFor={field.id}>
15 {label}
16 {field.required && <span className="required">*</span>}
17 </label>
18
19 <input
20 id={field.id}
21 name={field.name}
22 type={type}
23 defaultValue={field.defaultValue}
24 required={field.required}
25 minLength={field.minLength}
26 maxLength={field.maxLength}
27 pattern={field.pattern}
28 min={field.min}
29 max={field.max}
30 step={field.step}
31 aria-describedby={field.errors ? field.errorId : undefined}
32 />
33
34 {field.errors && (
35 <div id={field.errorId} className="field-errors">
36 {field.errors.map((error, i) => (
37 <p key={i} className="error-message">
38 {error}
39 </p>
40 ))}
41 </div>
42 )}
43 </div>
44 );
45}
46
47// Usage
48function MyForm() {
49 const { form, context } = useForm({
50 // ...
51 });
52
53 return (
54 <FormProvider context={form.context}>
55 <form {...form.props}>
56 <FormField name="firstName" label="First Name" />
57 <FormField name="email" label="Email" type="email" />
58 <FormField name="age" label="Age" type="number" />
59 </form>
60 </FormProvider>
61 );
62}
Nested field access
1import { useField } from '@conform-to/react/future';
2
3function AddressFields({ name }: { name: string }) {
4 const field = useField(name);
5 const address = field.getFieldset();
6
7 return (
8 <fieldset>
9 <legend>Address</legend>
10
11 <div>
12 <label htmlFor={address.street.id}>Street Address</label>
13 <input
14 id={address.street.id}
15 name={address.street.name}
16 defaultValue={address.street.defaultValue}
17 required={address.street.required}
18 />
19 {address.street.errors && (
20 <div className="error">{address.street.errors.join(', ')}</div>
21 )}
22 </div>
23
24 <div>
25 <label htmlFor={address.city.id}>City</label>
26 <input
27 id={address.city.id}
28 name={address.city.name}
29 defaultValue={address.city.defaultValue}
30 required={address.city.required}
31 />
32 {address.city.errors && (
33 <div className="error">{address.city.errors.join(', ')}</div>
34 )}
35 </div>
36
37 <div>
38 <label htmlFor={address.zip.id}>ZIP Code</label>
39 <input
40 id={address.zip.id}
41 name={address.zip.name}
42 defaultValue={address.zip.defaultValue}
43 pattern={address.zip.pattern}
44 required={address.zip.required}
45 />
46 {address.zip.errors && (
47 <div className="error">{address.zip.errors.join(', ')}</div>
48 )}
49 </div>
50 </fieldset>
51 );
52}
Array field handling
1import { useField } from '@conform-to/react/future';
2
3function TagInput({ name }: { name: string }) {
4 const field = useField(name);
5 const tagFields = field.getFieldList();
6
7 return (
8 <div>
9 <label>Tags</label>
10 {tagFields.map((tagField) => (
11 <div key={tagField.key}>
12 <input name={tagField.name} defaultValue={tagField.defaultValue} />
13 {tagField.errors && (
14 <span className="error">{tagField.errors.join(', ')}</span>
15 )}
16 </div>
17 ))}
18 </div>
19 );
20}
#Tips
Accessibility
The hook provides auto-generated IDs for proper ARIA associations:
- Use
id
for the input element andhtmlFor
on the label - Use
descriptionId
for help text (aria-describedby
) - Use
errorId
for error messages (aria-describedby
)