Form Input
FormInput is a set of thin wrappers that bind the input primitives to React Hook Form. Each wrapper reads the surrounding form context, so you pass a name (the field path) plus the underlying input’s props — value, onChange, and validation wiring are handled for you.
Use these instead of the raw inputs whenever a field lives inside a form, so state, errors, and submission stay consistent.
Because these require a form context to function, they’re documented here with usage code rather than a standalone live preview. For a full, runnable form see the Form page.
Available inputs
FormInput.Text, FormInput.Textarea, FormInput.Number, FormInput.Time, FormInput.Radio, FormInput.Checkbox, FormInput.Select, FormInput.MultiSelect — each maps to its corresponding primitive (TextInput, Textarea, NumberInput, TimeInput, Radio, Checkbox, Select, MultiSelect).
Installation
import { FormProvider, useForm } from "react-hook-form";import { FormInput, Button } from "@harnessio/ui/components";
function ConnectorForm() { const methods = useForm({ defaultValues: { name: "", type: "", enabled: false }, });
return ( <FormProvider {...methods}> <form onSubmit={methods.handleSubmit(console.log)}> <FormInput.Text name="name" label="Name" placeholder="my-connector" />
<FormInput.Select name="type" label="Type" options={[ { label: "GitHub", value: "github" }, { label: "GitLab", value: "gitlab" }, ]} />
<FormInput.Checkbox name="enabled" label="Enabled" />
<Button type="submit">Save</Button> </form> </FormProvider> );}Each wrapper forwards the full prop set of its underlying primitive — see the individual input pages (Text Input, Select, Checkbox, etc.) for the available props.
Anatomy
Each FormInput.* is its matching primitive wrapped by a withForm higher-order component that connects it to React Hook Form.
<FormProvider {...methods}> <form onSubmit={methods.handleSubmit(onSubmit)}> <FormInput.Text name="name" label="Name" /> </form></FormProvider>- Form binding — the wrapper renders a React Hook Form
Controllerfor the field named byname, reading the form’scontrolfrom context. The field’svalue,onChange,onBlur, andrefare wired in for you, so you only passnameplus the primitive’s own presentational props. - Context requirement — the wrapper calls
useFormContext()and throws if it’s not inside aFormProvider/FormWrapper. When a field doesn’t need form integration, use the standalone primitive instead. - Orientation — the wrapper reads
orientationfrom the surroundingFormWrapper, so fields line up vertically or horizontally to match the form. - Errors — the displayed error is the field’s validation message from the resolver, falling back to an explicit
errorprop if you pass one. - Special fields —
RadioandCheckboxmap the form field onto their own value/toggle props (onValueChangefor Radio;checked+onCheckedChangefor Checkbox), so they behave like every other bound field.
Best practices
Do
- Reach for
FormInput.*for any field inside a form, and the raw primitive only when a control lives outside form context. - Match each
nameto the corresponding key in your validation schema so errors attach to the right field. - Let the wrapper surface validation messages rather than wiring
errorby hand — passerroronly for messages that don’t come from the resolver.
Don’t
- Don’t render a
FormInput.*outside aFormProvider/FormWrapper— it will throw. - Don’t manage a field’s
value/onChangeyourself; theControllerowns them once you providename.
Content
- Give every field a
labelthat names it clearly; the wrapped primitive renders and associates it for you. - Keep placeholder text as an example of the expected value, not as a replacement for the label.
Accessibility
Each wrapper is presentationally identical to its underlying primitive — labels, input types, and validation wiring come from the wrapped Text Input, Select, Checkbox, and so on.
Labeling
- The
labeland error message are associated with the control by the underlying primitive, so assistive tech announces the field and its error together.
Known limitations
- Behavior depends on the wrapped primitive.
FormInputadds form binding, not new interaction semantics — keyboard and focus behavior are exactly those of the underlying input.
Properties
Common props
Every FormInput.* accepts these, plus all props of the primitive it wraps.
Prop | Required | Default | Type |
|---|---|---|---|
| name | true | string | |
| error | false | string | |
| label | false | string | |
| ...inputProps | false | props of the underlying input |
Available inputs
Prop | Required | Default | Type |
|---|---|---|---|
| FormInput.Text | false | Component | |
| FormInput.Textarea | false | Component | |
| FormInput.Number | false | Component | |
| FormInput.Time | false | Component | |
| FormInput.Radio | false | Component | |
| FormInput.Checkbox | false | Component | |
| FormInput.Select | false | Component | |
| FormInput.MultiSelect | false | Component |