BaseControl
The
BaseControlcomponent is part of Conform's future export. These APIs are experimental and may change in minor versions. Learn more
A React component that renders hidden native form controls. It could be used with useControl to bridge custom UI components back to standard form submission.
1import { BaseControl, useControl } from '@conform-to/react/future';
2
3const control = useControl({
4 defaultValue: 'initial value',
5});
6
7<BaseControl
8 name="title"
9 ref={control.register}
10 defaultValue={control.defaultValue}
11/>;#Props
name: string
Name used for the rendered hidden control(s).
defaultValue: unknown
Default value used to render the hidden control(s).
type?: 'text' | 'file' | 'fieldset' | 'select' | 'textarea' | ...
Controls which hidden element is rendered:
fieldset: renders a hidden<fieldset>and recursively renders nested hidden<input>elements fromdefaultValueselect: renders a hidden<select>textarea: renders a hidden<textarea>- otherwise: renders a hidden
<input type={type}>
form?: string
Form id to associate the hidden control(s) with when rendered outside the <form> element.
#Examples
Hidden text input for simple values
1const control = useControl({
2 defaultValue: field.defaultValue,
3});
4
5return (
6 <>
7 <BaseControl
8 name={field.name}
9 ref={control.register}
10 defaultValue={control.defaultValue}
11 />
12 <CustomTextInput
13 value={control.value ?? ''}
14 onChange={(value) => control.change(value)}
15 onBlur={() => control.blur()}
16 />
17 </>
18);Hidden fieldset for structured values
For type="fieldset", object and array shapes are expanded into nested names like range.start and members[0].id.
control.defaultValue drives the hidden inputs that are rendered, while control.payload is the current logical value exposed to your custom component.
1const control = useControl({
2 defaultValue: field.defaultPayload,
3 parse(payload) {
4 return DateRangeSchema.parse(payload);
5 },
6});
7
8return (
9 <>
10 <BaseControl
11 type="fieldset"
12 name={field.name}
13 ref={control.register}
14 defaultValue={control.defaultValue}
15 />
16 {/*
17 This renders a hidden fieldset with nested inputs:
18
19 <fieldset name="range" hidden>
20 <input name="range.start" value={control.defaultValue.start} />
21 <input name="range.end" value={control.defaultValue.end} />
22 </fieldset>
23
24 */}
25 <CustomDateRangePicker
26 value={control.payload}
27 onChange={(value) => control.change(value)}
28 onBlur={() => control.blur()}
29 />
30 </>
31);