Inputs & Forms
React Hook Form integration

Use with React Hook Form

💡️

React Hook Form (opens in a new tab) is a popular package developers use to validate forms. Koval UI input and form API is compatible with this package.

Validate field

Example of a single field validation.

import {useForm} from 'react-hook-form';
import {Form as KovalForm, InputText, Button, FormField} from 'koval-ui';
// Handle form successful submit
const onSubmit = (data) => console.log(data);
export default () => {
    /**
     * React hook form basic setup. Click Submit to validate.
     * @see https://react-hook-form.com/docs/useform
     */
    const {
        getFieldState,
        register,
        handleSubmit,
        formState: {errors},
    } = useForm({
        /**
         * Mode 'all' is recommended to use with Koval UI
         * @see https://react-hook-form.com/docs/useform#mode
         */
        mode: 'all',
    });
    /**
     * Get validation state from React Hook Form
     * @see https://react-hook-form.com/docs/useform/getfieldstate
     */
    const {invalid, isTouched} = getFieldState('exampleHint');
    // Convert React Hook Form validation state to Koval UI
    const validation = (() => {
        if (invalid) {
            // trigger an error for the input
            return 'error';
        } else if (!isTouched) {
            // don't show successful validation, when input value is unchanged
            return 'pristine';
        }
        // everything else considered to be successful validation
        return 'valid';
    })();
    return (
        <KovalForm onSubmit={handleSubmit(onSubmit)}>
            <FormField
                required
                label="Error message demo"
                // Display hook form errors as hint message below input
                hint={errors.exampleHint?.message}>
                <InputText
                    placeholder="More than 3 symbols"
                    autoComplete="off"
                    {...register('exampleHint', {
                        required: 'This field is required!',
                        minLength: {value: 3, message: 'Minimum 3 symbols'},
                    })}
                    // Synchronize input validation state with React Hook Form
                    validation={validation}
                    // Set browser input error message
                    errorMessage={errors.exampleHint?.message}
                />
            </FormField>
            <div>
                <Button type="submit">Submit</Button>
            </div>
        </KovalForm>
    );
};

Validate state with schema

React hook form is capable of doing complex schema-based validations. Here is an example using yup (opens in a new tab).

import {useCallback} from 'react';
import {Form as KovalForm, InputText, Button, FormField, InputNumber} from 'koval-ui';
import {useForm} from 'react-hook-form';
import {yupResolver} from '@hookform/resolvers/yup';
import * as yup from 'yup';
/**
 * Form validation schema
 * @see https://github.com/jquense/yup?tab=readme-ov-file#schema-basics
 */
const schema = yup
    .object({
        firstName: yup.string().required('Required field!').min(3, 'Minimum 3 symbols'),
        age: yup
            .number()
            .transform((value, originalValue) => {
                // Remove commas and convert to number
                return originalValue === '' ? null : value;
            })
            .required('Required field!')
            .moreThan(99, 'More than 99')
            .typeError('Age must be a number'),
    })
    .required();
// Handle form successful submit
const onSubmit = (data) => console.log(data);
/**
 * Utility function to determine the ValidationState of a form field based on its invalid and isTouched properties
 */
const getValidation = ({
    invalid,
    isTouched,
}) => {
    if (invalid) {
        // trigger an error for the input
        return 'error';
    } else if (!isTouched) {
        // don't show successful validation, when input value is unchanged
        return 'pristine';
    }
    // everything else considered to be successful validation
    return 'valid';
};
export default () => {
    /**
     * React hook form basic setup
     * @see https://react-hook-form.com/docs/useform
     */
    const {register, handleSubmit, formState, getFieldState, reset} = useForm({
        // Set schema validation with yup
        resolver: yupResolver(schema),
        defaultValues: {
            firstName: undefined,
            age: undefined,
        },
        mode: 'all',
    });
    const firstNameValidity = getValidation(getFieldState('firstName'));
    const ageValidity = getValidation(getFieldState('age'));
    const handleReset = useCallback(() => {
        // Handle form reset with RHF
        reset();
    }, [reset]);
    return (
        <KovalForm onSubmit={handleSubmit(onSubmit)}>
            <FormField
                label="First name"
                // Set conditional hint from React Hook Form state
                hint={formState.errors.firstName?.message}>
                <InputText
                    {...register('firstName')}
                    // Synchronize input validation state with React Hook Form
                    validation={firstNameValidity}
                    // Set browser input error message
                    errorMessage={formState.errors.firstName?.message}
                />
            </FormField>
            <FormField label="Age" hint={formState.errors.age?.message}>
                <InputNumber
                    {...register('age')}
                    validation={ageValidity}
                    errorMessage={formState.errors.age?.message}
                />
            </FormField>
            <div>
                <Button type="submit">Submit</Button>
                <Button type="button" variant="alternative" onClick={handleReset}>
                    Reset
                </Button>
            </div>
        </KovalForm>
    );
};