Validation

You can setup validation on form or field level using the following propertes:

Field validation

Field level validation is useful for simple validation of single field value (e.g.: field is valid email). The validation function receives value as first argument and expects validation message to be returned if value is not valid.

import React from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@progress/kendo-react-form';
import { Input } from '@progress/kendo-react-inputs';

const emailRegex = new RegExp(/\S+@\S+\.\S+/);
const emailValidator = (value) => (emailRegex.test(value) ? "" : "Please enter a valid email.");
const EmailInput = (fieldRenderProps) => {
    const { validationMessage, visited, ...others } = fieldRenderProps;
    return (
        <div>
            <Input {...others} />
            {
                visited && validationMessage &&
                (<div className={"k-required"}>{validationMessage}</div>)
            }
        </div>
    );
};
const App = () => {
    const handleSubmit = (dataItem) => alert(JSON.stringify(dataItem, null, 2));
    return (
        <Form
            onSubmit={handleSubmit}
            render={(formRenderProps) => (
                <form onSubmit={formRenderProps.onSubmit} className={'k-form'}>
                    <fieldset>
                        <legend>Please fill in the email field:</legend>
                        <div className="mb-3">
                            <Field name={"email"} type={"email"} component={EmailInput} label={"Email"} validator={emailValidator} />
                        </div>
                    </fieldset>
                    <button
                        type={'submit'}
                        className="k-button"
                        disabled={!formRenderProps.allowSubmit}
                    >
                        Submit
                    </button>
                </form>
            )}
        />
    );
};
ReactDOM.render(
    <App />,
    document.querySelector('my-app')
);

FieldArray validation

Field array level validation is useful for simple validation of arrays (e.g.: array have at least one record). The validation function receives value as first argument and expects validation message to be returned if value is not valid.

import React from 'react';
import ReactDOM from 'react-dom';
import { Form, Field, FieldArray, FieldArrayRenderProps } from '@progress/kendo-react-form';
import { Input } from '@progress/kendo-react-inputs';
import { Grid, GridColumn, GridToolbar } from '@progress/kendo-react-grid';

const arrayLengthValidator = (value) => (value && value.length ? "" : "Please add at least one record.");

const nameCell = (props) => {
    return (
        <td>
            <Field
                component={Input}
                name={`users[${props.dataIndex}].${props.field}`}
            />
        </td>
    );
};

const commandCell = (onRemove) => (props) => {
    const onClick = React.useCallback(
        () => onRemove(props),
        [onRemove]
    );
    return (
        <td>
            <button
                className="k-button k-grid-remove-command"
                onClick={onClick}
            >
                Remove
            </button>
        </td>
    );
};

const FormGrid = (fieldArrayRenderProps) => {
    const { validationMessage, visited } = fieldArrayRenderProps;
    const onAdd = React.useCallback(
        () => fieldArrayRenderProps.onUnshift({ value: { name: '' } }),
        [fieldArrayRenderProps.onUnshift]
    );
    const onRemove = React.useCallback(
        (cellProps) => fieldArrayRenderProps.onRemove({ index: cellProps.dataIndex }),
        [fieldArrayRenderProps.onRemove]
    );

    return (
        <div>
            {
                visited && validationMessage &&
                (<div className={"k-required"}>{validationMessage}</div>)
            }
            <Grid
                data={fieldArrayRenderProps.value}
            >
                <GridToolbar>
                    <button title="Add new" className="k-button k-primary" onClick={onAdd} >
                        Add new
                    </button>
                </GridToolbar>
                <GridColumn field="name" title="Name" cell={nameCell} />
                <GridColumn cell={commandCell(onRemove)} width="240px" />
            </Grid>
        </div>
    );
};

export const App = () => {
    const handleSubmit = (dataItem) => alert(JSON.stringify(dataItem));
    return (
        <Form
            initialValues={{
                users: []
            }}
            onSubmit={handleSubmit}
            render={(formRenderProps) => (
                <div>
                    <FieldArray
                        name="users"
                        component={FormGrid}
                        validator={arrayLengthValidator}
                    />
                    <button
                        className="k-button"
                        disabled={!formRenderProps.allowSubmit}
                        onClick={formRenderProps.onSubmit}
                    >
                        Submit
                    </button>
                </div>
            )}
        />
    );
};
ReactDOM.render(
    <App />,
    document.querySelector('my-app')
);

Form validation

Form validation can be used for complex validation between more fields, where using the field level validation is not convenient.

import React from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@progress/kendo-react-form';
import { Input } from '@progress/kendo-react-inputs';
import { getter } from '@progress/kendo-react-common';

const firstNameGetter = getter('user.firstName');
const lastNameGetter = getter('user.lastName');
const firstOrLastNameValidator = (values) => {
    if (firstNameGetter(values) || lastNameGetter(values)) {
        return {};
    }

    return {
        VALIDATION_SUMMARY: 'Please fill at least one of the following fields.',
        ['user.firstName']: 'Please check the validation summary for more information.',
        ['user.lastName']: 'Please check the validation summary for more information.'
    };
};

const ValidatedInput = (fieldRenderProps) => {
    const { validationMessage, visited, ...others } = fieldRenderProps;
    return (
        <div>
            <Input {...others} />
            {
                visited && validationMessage &&
                (<div className={"k-required"}>{validationMessage}</div>)
            }
        </div>
    );
};

const App = () => {
    const handleSubmit = (dataItem) => alert(JSON.stringify(dataItem, null, 2));
    return (
        <Form
            onSubmit={handleSubmit}
            validator={firstOrLastNameValidator}
            render={(formRenderProps) => (
                <form onSubmit={formRenderProps.onSubmit} className={'k-form'}>
                    <fieldset>
                        <legend>Please fill in the following information:</legend>
                        {
                            formRenderProps.visited && formRenderProps.errors && formRenderProps.errors.VALIDATION_SUMMARY &&
                            (<div className={"k-required"}>{formRenderProps.errors.VALIDATION_SUMMARY}</div>)
                        }
                        <div className="mb-3">
                            <Field name={'user.firstName'} component={ValidatedInput} label={'First name'} />
                        </div>
                        <div className="mb-3">
                            <Field name={'user.lastName'} component={ValidatedInput} label={'Last name'} />
                        </div>
                    </fieldset>
                    <button
                        type={'submit'}
                        className="k-button"
                        disabled={!formRenderProps.allowSubmit}
                    >
                        Submit
                    </button>
                </form>
            )}
        />
    );
};
ReactDOM.render(
    <App />,
    document.querySelector('my-app')
);