Docs
API

Hook API

useForm

The useForm hook takes an object UseFormConfig<FormValues> with two properties: initialValues and validation. The initialValues property is an object containing the initial values of the form fields. The validation property is an optional object containing validation rules for the form fields.

Parameters:

input
An object containing the initial values of the form fields as well as the input type.

  • type
    The type field of the input object describes the form input strategy. The 2 options are: controlled and uncontrolled. It defaults to uncontrolled for optimal performance.

  • initialValues
    The initialValues property is required. This represents the default values for the form upon initialization.

  • watch
    The watch field can only utilized if your using the uncontrolled input type strategy. This allows you to specify specific fields that you need to behave as though they are controlled fields and alert subscribers to all changes in the fields values. There are several options available when utilizing this API.

validation
An optional object containing validation rules for the form fields. It has several fields and some of which are optional.

  • type
    The type field of the validation object describes how and when the form fields should be validated. The 3 options are: change, blur, and submit. It defaults to change.

  • schema
    The schema is required if the validation parameter is provided. These are the rules provided to the hook that describe how the form fields should be validated. Technically it is just a callback function that receives the current form values as an argument, and returns an object with an errors key.

  • debounce
    This is another optional field for the validation object and can only be provided when the validation type is change. It allows you to express the amount of time to debounce when a fields value is being changed both in and out of the form field's validation.

Types:

// input
type FormValues<TValues extends { [key: string]: any }> = {
  [K in keyof TValues]: TValues[K];
};
 
type FormInputType = 'controlled' | 'uncontrolled';
 
type BaseFormInput<TValues extends FormValues<any>> = {
  initialValues: TValues;
};
 
type ControlledFormInput<TValues extends FormValues<any>> = BaseFormInput<TValues> & {
  type?: Extract<FormInputType, 'controlled'>;
};
 
type WatchConfig<TValues extends FormValues<any>, K extends keyof TValues> = {
  [key in K]: (value: TValues[key], prevValue: TValues[key]) => boolean;
};
 
type UncontrolledFormInput<TValues extends FormValues<any>> = BaseFormInput<TValues> & {
  type?: Extract<FormInputType, 'uncontrolled'>;
  watch?:
    | (keyof TValues | Partial<WatchConfig<TValues, keyof TValues>>)[]
    | Partial<WatchConfig<TValues, keyof TValues>>;
};
 
type FormInput<TValues extends FormValues<any>> =
  | ControlledFormInput<TValues>
  | UncontrolledFormInput<TValues>;
 
// validation
type Debounce =
  | number
  | {
      in: number;
      out: number;
    };
 
type ValidatorResult<TValues extends FormValues<any>> = {
  errors: {
    [K in keyof TValues]?: string;
  };
};
 
type BaseValidation<TValues extends FormValues<any>> = {
  schema: (values: TValues) => ValidatorResult<TValues>;
};
 
type ChangeValidation<TValues extends FormValues<any>> = BaseValidation<TValues> & {
  type?: 'change';
  debounce?: Debounce;
};
 
type BlurValidation<TValues extends FormValues<any>> = BaseValidation<TValues> & {
  type?: 'blur';
};
 
type SubmitValidation<TValues extends FormValues<any>> = BaseValidation<TValues> & {
  type?: 'submit';
};
 
type Validation<TValues extends FormValues<any>> =
  | ChangeValidation<TValues>
  | BlurValidation<TValues>
  | SubmitValidation<TValues>;

Usage:

import { useForm } from '@react-form-ally/hook';
 
type FormValues = {
  email: string;
  password: string;
};
 
// Basic example
const form = useForm<FormValues>({
  input: {
    initialValues: {
      email: '',
      password: '',
    },
    type: 'controlled', // defaults to uncontrolled and can be omitted
  },
  validation: {
    type: 'change', // defaults to change and can be omitted
    debounce: {
      in: 500,
      out: 0,
    },
    schema: (values) => {
      return {
        errors: {
          email: 'Email is required',
        }
      };
    }
  }
});
 
// Watch config example - array of field names
const form = useForm<FormValues>({
  input: {
    initialValues: {
      email: '',
      password: '',
    },
    type: 'uncontrolled',
    watch: ['email'],
  },
  ...validationConfig
});
 
// Watch config example - object of field names with a value of (fieldValue, previousFieldValue) => boolean
const form = useForm<FormValues>({
  input: {
    initialValues: {
      email: '',
      password: '',
    },
    type: 'uncontrolled',
    watch: {
      email: (value, prevValue) => true,
    },
  },
  ...validationConfig
});
 
// Watch config example - array of combined items in examples above
const form = useForm<FormValues>({
  input: {
    initialValues: {
      email: '',
      password: '',
    },
    type: 'uncontrolled',
    watch: [
      'email',
      {
        password: (value, prevValue) => value !== prevValue,
      },
    ],
  },
  ...validationConfig
});

createFormHook

The createFormHook function accepts the exact same input as useForm and returns a fully typed form hook. Using the createFormHook function allows you to store form state in an external store, persisting that state between multiple components without the need of a context provider. Simply initialize, store, import, and use the result from createFormHook.

import { useForm, createFormHook } from '@react-form-ally/hook';
 
type FormValues = {
  email: string;
  password: string;
};
 
const useLogin = createFormHook<FormValues>({
  input: {
    initialValues: { email: '', password: '' },
    type: 'controlled', // defaults to uncontrolled and can be omitted
  },
  validation: {
    type: 'change', // defaults to change and can be omitted
    debounce: { in: 500, out: 0 },
    schema: (values) => {
      return {
        errors: {
          email: 'Email is required',
          password: 'Password is required',
        },
      };
    }
  }
});
 
const StepOne: React.FC = () => {
  const { touched, errors, registerInput } = useLogin();
 
  return (
    <form>
      <input {...registerInput('email', { type: 'email' })} />
      {touched.email && errors.email && <div>{errors.email}</div>}
 
      <a href="/step-two">
        Next
      </a>
    </form>
  );
};
 
const StepTwo: React.FC = () => {
  const { onSubmit, touched, errors, valid, registerInput } = useLogin();
 
  const handleSubmit = (formValues: FormValues) => {
    console.log('Submitting form...', formValues);
  };
 
  return (
    <form onSubmit={onSubmit(handleSubmit)}>
      <input {...registerInput('password', { type: 'password' })} />
      {touched.password && errors.password && <div>{errors.password}</div>}
 
      <button type="submit" disabled={!valid}>
        Submit
      </button>
    </form>
  );
};

registerInput

The registerInput function is a utility function for registering form fields and their properties in a type-safe manner. This should be used to register all input types besides either checkbox or radio. It takes in two arguments - fieldName and options - and returns a RegisterInputResult.

  • fieldName
    Represents the name attribute of the form field. It is a union type of all the keys in the generic object passed to useForm.

  • options (optional)
    An optional object that can have any of the following properties: id, required, disabled, max, maxLength, min, minLength, pattern, placeholder, readOnly, and type. Each of these properties represent supported HTML form field attributes and are simply spread onto the registered field.

The RegisterInputResult by default will add the following four properties to a form field: name, onChange, onBlur, and value or defaultValue (depends on input strategy type being either controlled or uncontrolled).

  • name
    Represents the name of the field.

  • onChange
    A ChangeEventHandler<any> function that is called when the field value changes.

  • onBlur
    A FocusEventHandler<any> function that is called when the field loses focus.

  • value | defaultValue
    A string or a number that represents the current or default value of the field.

  • ref
    The ref property which is used to store a reference to the input element in the DOM.

Types:

type RegisterFieldOptions = {
  id?: string;
  required?: boolean;
  disabled?: boolean;
};
 
type RegisterInputOptions = RegisterFieldOptions & {
  max?: number | string;
  maxLength?: number;
  min?: number | string;
  minLength?: number;
  pattern?: string;
  placeholder?: string;
  readOnly?: boolean;
  type?: 'text' | 'email' | 'number' | 'password' | 'tel' | 'url';
};
 
type RegisterFieldResult = RegisterFieldOptions & {
  name: string;
  ref: (node: HTMLInputElement) => void;
  onChange: ChangeEventHandler<any>;
  onBlur: FocusEventHandler<any>;
};
 
type RegisterInputResult = RegisterFieldResult &
  RegisterInputOptions & {
    value?: string | number;
    defaultValue?: string | number;
  };
const { registerInput } = useForm({
 // ...
});
 
return (
  <form>
    <input {...registerInput('email', { id: 'email', required: true, type: 'email' })} />
    {/* ... */}
  </form>
);

registerCheckbox

The registerCheckbox function is a utility function for registering checkbox form fields and their properties in a type-safe manner. It takes in two arguments - fieldName and options - and returns a RegisterCheckboxResult.

  • fieldName
    Represents the name attribute of the form field. It is a union type of all the keys in the generic object passed to useForm.

  • options (optional)
    An optional object that can have any of the following properties: id, required, disabled, type, and value. Each of these properties represent supported HTML checkbox input element attributes and are simply spread onto the registered checkbox.

The RegisterCheckboxResult by default will add the following four properties to a form field: name, onChange, onBlur, and checked or defaultChecked (depends on input strategy type being either controlled or uncontrolled).

  • name
    Represents the name of the field.

  • onChange
    A ChangeEventHandler<any> function that is called when the field value changes.

  • onBlur
    A FocusEventHandler<any> function that is called when the field loses focus.

  • checked | defaultChecked
    A string or a number that represents the current or default checked value of the field.

  • ref
    The ref property which is used to store a reference to the input element in the DOM.

Types:

type RegisterFieldOptions = {
  id?: string;
  required?: boolean;
  disabled?: boolean;
};
 
type RegisterCheckboxOptions = RegisterFieldOptions & {
  type?: 'checkbox';
  value?: string;
};
 
type RegisterFieldResult = RegisterFieldOptions & {
  name: string;
  ref: (node: HTMLInputElement) => void;
  onChange: ChangeEventHandler<any>;
  onBlur: FocusEventHandler<any>;
};
 
type RegisterCheckboxResult = RegisterFieldResult &
  RegisterCheckboxOptions & {
    checked?: boolean;
    defaultChecked?: boolean;
  };
const { registerCheckbox } = useForm({
 // ...
});
 
return (
  <form>
    <label htmlFor="save-profile">
      <input {...registerCheckbox('saveProfile', { type: 'checkbox', id: 'save-profile' })} />
      Save profile?
    </label>
    {/* ... */}
  </form>
);

registerRadio

The registerRadio function is a utility function for registering radio form fields and their properties in a type-safe manner. It takes in two arguments - fieldName and options - and returns a RegisterCheckboxResult.

  • fieldName
    Represents the name attribute of the form field. It is a union type of all the keys in the generic object passed to useForm.

  • options (value option is required for radio inputs)
    An optional object that can have any of the following properties: id, required, disabled, type, and value. Each of these properties represent supported HTML radio input element attributes and are simply spread onto the registered radio.

The RegisterRadioResult by default will add the following four properties to a form field: name, onChange, onBlur, and checked or defaultChecked (depends on input strategy type being either controlled or uncontrolled).

  • name
    Represents the name of the field.

  • onChange
    A ChangeEventHandler<any> function that is called when the field value changes.

  • onBlur
    A FocusEventHandler<any> function that is called when the field loses focus.

  • checked | defaultChecked
    A string or a number that represents the current or default checked value of the field.

  • ref
    The ref property which is used to store a reference to the input element in the DOM.

Types:

type RegisterFieldOptions = {
  id?: string;
  required?: boolean;
  disabled?: boolean;
};
 
type RegisterRadioOptions = RegisterFieldOptions & {
  type?: 'radio';
  value: string;
};
 
type RegisterFieldResult = RegisterFieldOptions & {
  name: string;
  ref: (node: HTMLInputElement) => void;
  onChange: ChangeEventHandler<any>;
  onBlur: FocusEventHandler<any>;
};
 
type RegisterRadioResult = RegisterFieldResult &
  RegisterRadioOptions & {
    checked?: boolean;
    defaultChecked?: boolean;
  };
const { registerRadio } = useForm({
 // ...
});
 
return (
  <form>
    <label htmlFor="radio-pizza">
      <input
        {...registerRadio('favoriteFood', {
          value: 'pizza',
          type: 'radio',
          id: 'radio-pizza',
        })}
      />
      Pizza
    </label>
    <label htmlFor="radio-french-fries">
      <input
        {...registerRadio('favoriteFood', {
          value: 'frenchFries',
          type: 'radio',
          id: 'radio-french-fries',
        })}
      />
      French Fries
    </label>
    {/* ... */}
  </form>
);

onSubmit

The onSubmit option is a function takes a callback function as a parameter. The callback function will be called when the form is submitted, and will receive the current values of the form fields as a parameter.

Types:

type Submit<TValues extends FormValues<any>> = (
  handler: (formValues: TValues) => void
) => (e: FormEvent) => void;

Usage:

const { onSubmit } = useForm({
 // ...
});
 
const handleSubmit = (formValues: FormValues) => {
  // ...
}
 
return (
  <form onSubmit={onSubmit(handleSubmit)}>
    {/* ... */}
  </form>
);

onReset

The onReset handler is a function that resets the form to its initial values. This could simply be tied to your form via the form element's onReset method, or called programmatically whenever you need to reset form state entirely. This will include any value, validation, or touched state.

Types:

type Reset = () => void;

Usage:

const { onReset } = useForm({
 // ...
});
 
return (
  <form onReset={onReset}>
    {/* ... */}
  </form>
);

focusField

A helper function that can assist in focusing on any field registered within a given form.

Types:

type FocusField = (name: keyof TValues) => void;

Usage:

const { registerInput, focusField } = useForm({
 // ...
});
 
useEffect(() => {
  focusField('name');
}, []);
 
return (
  <form>
    <input {...registerInput('name', { id: 'name', type: 'text' })} />
    {/* ... */}
  </form>
);

resetValues

A helper function that resets the form value state to it's initial values without making any changes or updates to the error and touched states. It takes no arguments and returns nothing (i.e., it has a return type of void). It can be used as a drop in replacement for the onReset method or whatever use case you might have for dynamically resetting form values.

Types:

type ResetValues = () => void;

Usage:

const { onSubmit, resetValues } = useForm({
 // ...
});
 
const handleSubmit = (formValues: FormValues) => {
  // ...
  resetValues();
}
 
return (
  <form onSubmit={onSubmit(handleSubmit)}>
    {/* ... */}
  </form>
);

resetErrors

A helper function that resets the form error state to it's initial values without making any changes or updates to the values and touched states. It takes no arguments and returns nothing (i.e., it has a return type of void). It can be used as a drop in replacement for the onReset method or whatever use case you might have for dynamically resetting form errors.

Types:

type ResetErrors = () => void;

Usage:

const { onSubmit, resetErrors } = useForm({
 // ...
});
 
const handleSubmit = (formValues: FormValues) => {
  // ...
  resetErrors();
}
 
return (
  <form onSubmit={onSubmit(handleSubmit)}>
    {/* ... */}
  </form>
);

resetTouched

A helper function that resets the form touched state to it's initial values without making any changes or updates to the values and error states. It takes no arguments and returns nothing (i.e., it has a return type of void). It can be used as a drop in replacement for the onReset method or whatever use case you might have for dynamically resetting form errors.

Types:

type ResetTouched = () => void;

Usage:

const { onSubmit, resetTouched } = useForm({
 // ...
});
 
const handleSubmit = (formValues: FormValues) => {
  // ...
  resetTouched();
}
 
return (
  <form onSubmit={onSubmit(handleSubmit)}>
    {/* ... */}
  </form>
);

setFieldValue

A function that sets a value for a specific field in a form. It takes three parameters:

  • name
    The name of the field to set the value for.

  • value
    The value to set for the field.

  • shouldValidate
    An optional boolean parameter that specifies whether the field should be validated after setting its value. Defaults to true.

The setFieldValue function can be used in a generic way to define a function that sets the value for any field in a form.

Types:

type SetValue<TValues extends FormValues<any>, K extends keyof TValues> = (
  name: K,
  value: TValues[K],
  shouldValidate?: boolean
) => void;

Usage:

const { setFieldValue } = useForm({
 // ...
});
 
useEffect(() => {
  let ignore = false;
  fetch('http://myapi.com/user/1')
    .then(res => res.json())
    .then((json) => {
      if (!ignore) {
        const email = json.data?.user?.email;
        setFieldValue('email', email);
      }
    });
  return () => {
    ignore = true;
  };
}, [url]);
// ...

setFieldsValues

A function that sets the value of multiple form fields. It takes two arguments:

  • values
    A partial object of TValues, which is a generic type parameter of FormValues<any>.

  • shouldValidation (optional)
    A boolean flag indicating whether to trigger validation after setting the values.

The setFieldsValues function returns nothing (i.e., it has a return type of void). It's much like setFieldValue, except it can be used to set the values of multiple form fields simultaneously.

Types:

type SetValues<TValues extends FormValues<any>> = (
  values: Partial<TValues>,
  shouldValidation?: boolean
) => void;

Usage:

const { setFieldsValues } = useForm({
 // ...
});
 
useEffect(() => {
  let ignore = false;
  fetch('http://myapi.com/user/1')
    .then(res => res.json())
    .then((json) => {
      if (!ignore) {
        const name = json.data?.user?.name;
        const email = json.data?.user?.email;
        setFieldsValues({ name, email });
      }
    });
  return () => {
    ignore = true;
  };
}, [url]);
// ...

setFieldError

A function that sets an error message for a single form field. It takes 2 parameters:

  • name
    The name of the field to set the value for.

  • value
    The value to set for the field.

The setFieldError function can be used in a generic way to define a function that sets the value for any field in a form.

Types:

type SetError<TValues extends FormValues<any>> = (
  name: keyof TValues,
  value: string
) => void;

Usage:

const { setFieldError } = useForm({
 // ...
});
 
useEffect(() => {
  let ignore = false;
  fetch('http://myapi.com/user/1')
    .then(res => res.json())
    .then(() => {
      // ...
    })
    .catch(() => {
      if (ignore) return;
      setFieldError('email', 'Invalid email.');
    });
  return () => {
    ignore = true;
  };
}, [url]);
// ...

setFieldsErrors

A function that sets error messages for multiple form fields. It takes a single argument:

  • values
    A partial object of TValues, which is a generic type parameter of FormValues<any>.

The setFieldsErrors function returns nothing (i.e., it has a return type of void). It's much like setFieldError, except it can be used to set the errors of multiple form fields simultaneously.

Types:

type SetErrors<TValues extends FormValues<any>> = (
  values: Partial<Record<keyof TValues, string>>
) => void;

Usage:

const { setFieldsErrors } = useForm({
 // ...
});
 
useEffect(() => {
  let ignore = false;
  fetch('http://myapi.com/user/1')
    .then(res => res.json())
    .then(() => {
      // ...
    })
    .catch(() => {
      if (ignore) return;
      setFieldsErrors({ email: 'Invalid email' });
    });
  return () => {
    ignore = true;
  };
}, [url]);
// ...

setFieldTouched

A function that sets the touched state for a single form field. It takes 2 parameters:

  • name
    The name of the field to set the touched state for.

  • value
    The value to set for the field.

The setFieldTouched function can be used in a generic way to define a function that sets the value for any field in a form.

Types:

type SetFieldTouched<TValues extends FormValues<any>> = (
  name: keyof TValues,
  value: boolean
) => void;

Usage:

const { setFieldTouched } = useForm({
 // ...
});
 
useEffect(() => {
  let ignore = false;
  fetch('http://myapi.com/user/1')
    .then(res => res.json())
    .then(() => {
      // ...
      if (ignore) return;
      setFieldTouched('email', true);
    })
  return () => {
    ignore = true;
  };
}, [url]);
// ...

setFieldsTouched

A function that sets the touched state for multiple form fields. It takes a single parameter.

  • values
    A partial object of where the keys match those of type FormValues<any>, and the values are a boolean;

The setFieldsTouched function returns nothing (i.e., it has a return type of void). It's much like setFieldTouched, except it can be used to set the touched state of multiple form fields simultaneously.

Types:

type SetTouched<TValues extends FormValues<any>> = (values: {
  [K in keyof TValues]: boolean;
}) => void;

Usage:

const { setFieldsTouched } = useForm({
 // ...
});
 
useEffect(() => {
  let ignore = false;
  fetch('http://myapi.com/user/1')
    .then(res => res.json())
    .then(() => {
      // ...
      if (ignore) return;
      setFieldTouched({ email: true });
    })
  return () => {
    ignore = true;
  };
}, [url]);
// ...

values

An object containing the current values state of the form. The generic you provide will represent the values object for the instance of useForm.

Types:

type FormValues<TValues extends { [key: string]: any }> = {
  [K in keyof TValues]: TValues[K];
};

Usage:

type FormValues = {
  email: string;
}
 
const { values, registerField } = useForm<FormValues>({
 initialValues: {
   email: '',
 },
});
 
return (
  <form>
    <input type="email" {...registerField('email')} />
    {values.email && <div>Current value: {values.email}</div>}
    // ..
  </form>
);

errors

An object containing the current error state of the form. The generic you provide will represent the keys of the error object for the instance of useForm. The value will be of type string and will represent the error message for that form field.

Types:

type FormErrors<TValues extends FormValues<any>> = {
  [K in keyof TValues]?: string;
};

Usage:

type FormValues = {
  email: string;
}
 
const { errors, registerField } = useForm<FormValues>({
 initialValues: {
   email: '',
 },
});
 
return (
  <form>
    <input type="email" {...registerField('email')} />
    {errors.email && <div>{errors.email}</div>}
    // ..
  </form>
);

touched

An object containing the current touched state of the form. The generic you provide will represent the keys of the touched state object for the instance of useForm. The value will be of type boolean and will represent whether the form field has been touched.

Types:

type FormTouched<TValues extends FormValues<any>> = {
  [K in keyof TValues]?: boolean;
};

Usage:

type FormValues = {
  email: string;
}
 
const { touched, errors, registerField } = useForm<FormValues>({
  initialValues: {
   email: '',
  },
});
 
return (
  <form>
    <input type="email" {...registerField('email')} />
    {touched.email && errors.email && <div>{errors.email}</div>}
    // ..
  </form>
);

valid

A boolean indicating whether the form is currently valid.

Types:

type Valid = boolean;
const { valid } = useForm({
 // ...
});
 
return (
  <form>
    // ...
    <button type="submit" disabled={!valid}>Submit</button>
  </form>
);

submitted

A boolean indicating whether the form has been submitted.

Types:

type Submitted = boolean;
const { submitted } = useForm({
 // ...
});
 
if (submitted) {
  return (
    <div>Your form has been successfully submitted!</div>
  );
}
 
return (
  <form>
    // ...
  </form>
);