Form
Coordinate field values, validation, submission, and reset behavior.
The Form component is an orchestration layer for the form controls in Mosmox UI. It keeps values together, connects fields to the same validation lifecycle, exposes consistent errors, and provides both declarative and imperative submission APIs.
Installation
import { Form, Input, Button } from '@mosmox/ui';Basic usage
Form.Field uses a render prop so it can wrap any existing control without replacing that control's API.
<Form
initialValues={{ email: '' }}
onSubmit={(values) => console.log(values)}
>
<Form.Field
name="email"
rules={[
{ required: true },
{ pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: 'Enter a valid email.' },
]}
>
{(field) => (
<Input
label="Email"
type="email"
value={String(field.value ?? '')}
error={field.error}
required={field.required}
name={field.name}
onChange={field.onChange}
onBlur={field.onBlur}
/>
)}
</Form.Field>
<Form.Actions>
<Button type="submit">Save</Button>
</Form.Actions>
</Form>The form prevents the browser's default navigation, validates registered fields, and calls onSubmit only when the result is valid. onInvalid receives a map of field names to messages.
Working with existing controls
The field adapter accepts native events as well as direct values. This makes it compatible with the existing form components:
<Form.Field name="name">{(field) => <Input {...field.controlProps} label="Name" />}</Form.Field>
<Form.Field name="team">{(field) => (
<Select
label="Team"
options={[{ value: 'design', label: 'Design' }]}
value={typeof field.value === 'string' ? field.value : undefined}
onChange={(value) => field.onChange(value)}
error={field.error}
/>
)}</Form.Field>
<Form.Field name="enabled">{(field) => (
<Switch checked={Boolean(field.value)} onChange={field.onChange} label="Enabled" />
)}</Form.Field>
<Form.Field name="terms">{(field) => (
<Checkbox checked={Boolean(field.value)} onChange={field.onChange} label="Accept terms" error={field.error} />
)}</Form.Field>The same pattern works with Textarea, InputNumber, InputPassword, InputOTP, InputMask, InputCurrency, ColorPicker, Radio, and other controls. Controls with a value callback can pass the value to field.onChange directly.
Validation
Rules run in declaration order. A rule can contain:
| Property | Type | Description |
|---|---|---|
required | boolean | Rejects empty values. |
message | string | Custom message for that rule. |
minLength | number | Minimum string length. |
maxLength | number | Maximum string length. |
pattern | RegExp | Regular expression constraint. |
validator | (value, values) => string | undefined | Promise<string | undefined> | Custom synchronous or asynchronous validation. |
Choose when validation runs with validateOn: submit (default), change, blur, or change-and-blur.
<Form validateOn="change-and-blur">
<Form.Field
name="username"
rules={[
{ required: true },
{ minLength: 3 },
{ validator: async (value) => isAvailable(String(value)) ? undefined : 'Name is already taken.' },
]}
>
{(field) => <Input {...field.controlProps} label="Username" />}
</Form.Field>
</Form>Values, reset, and submit
Use initialValues for the starting snapshot. Pass values when the parent owns the complete value object. onValuesChange reports the latest object and the field that changed.
const formRef = useRef<FormInstance>(null);
<Form ref={formRef} initialValues={{ query: '' }}>
{/* fields */}
</Form>
formRef.current?.setFieldValue('query', 'documentation');
const valid = await formRef.current?.validate();
await formRef.current?.submit();
formRef.current?.reset();The FormInstance also provides getValues, getFieldValue, getFieldError, setValues, and setFieldError for integration with wizards, autosave, and server-side errors.
Layout and configuration
Use layout="vertical" for the default stacked layout, horizontal for label/control rows, or inline for compact filters. size accepts sm, default, and lg. Set disabled on the form to disable the form's visual container and pass it to controls as needed.
<ConfigProvider components={{ form: { layout: 'horizontal', size: 'sm', validateOn: 'blur' } }}>
<Form>{/* all forms in this subtree use these defaults */}</Form>
</ConfigProvider>Individual props always override ConfigProvider defaults. The component uses the shared theme tokens and existing control error states, so it can be introduced incrementally into forms that already use Mosmox UI fields.
API reference
Form props
| Prop | Type | Default |
|---|---|---|
initialValues | Record<string, unknown> | {} |
values | Record<string, unknown> | — |
layout | vertical | horizontal | inline | vertical |
size | sm | default | lg | default |
validateOn | change | blur | submit | change-and-blur | submit |
disabled | boolean | false |
onValuesChange | (values, changedField) => void | — |
onSubmit | (values, event) => void | Promise<void> | — |
onInvalid | (errors) => void | — |
onReset | (values) => void | — |
Subcomponents
Form.Field— registers a named value and suppliesvalue,error,touched,validating,required,onChange,onBlur, andcontrolProps.Form.Actions— aligns submit/reset actions withstart,center,end, orbetween.