Getting Started with Forms

The HTML5 form element supports the validation of inputs that is based on a set of pre-defined rules.

All inputs get validated upon form submission and if the validation fails, the form submission is prevented. Out of the box, KendoReact delivers components which support the HTML5 form validation and also provide props for configuring a set of minimal requirements for a component to be in a valid state.

You can use the KendoReact components which provide forms support in the following scenarios:

Preventing Form Submission

Whenever the validity state of a component is invalid, the form submission gets prevented. The prevention of form submission enables you to achieve the same behavior as the native HTML form elements (such as input and select) and to avoid the explicit verification of the validity state in the onSubmit event handler.

The following example demonstrates how to prevent the form submission by passing the required prop to a component.

import * as React from 'react';
import * as ReactDOM from 'react-dom';

import { Input } from '@progress/kendo-react-inputs';
import { DropDownList } from '@progress/kendo-react-dropdowns';
import { Button } from '@progress/kendo-react-buttons';

import { countries } from './countries';

class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            success: false
        };
    }
    render() {
        return (
            <div className="row example-wrapper">
                <div className="col-xs-12 col-sm-6 offset-sm-3 example-col">
                    <div className="card">
                        <div className="card-block">
                            <form className="k-form" onSubmit={this.handleSubmit}>
                                <fieldset>
                                    <legend>Your Form:</legend>
                                    <label className="k-form-field">
                                        <span>A required Input</span>
                                        <Input
                                            name="input"
                                            required={true}
                                        />
                                    </label>
                                </fieldset>
                                <span>A required DropDownList</span>
                                <DropDownList
                                    name="ddl"
                                    required={true}
                                    data={countries}
                                    style={{ width: '100%' }}
                                />
                                <Button className="mt-3" type="submit" primary={true}>Submit</Button>
                            </form>
                        </div>
                    </div>
                </div>
                {this.state.success && (
                    <div
                        className="alert alert-success"
                        style={{ position: 'absolute' }}
                    >
                        Form submitted!
                    </div>)}
            </div>
        );
    }

    handleSubmit = (event) => {
        event.preventDefault();
        this.setState({ success: true });
        setTimeout(() => { this.setState({ success: false }); }, 3000);
    }
}

ReactDOM.render(
    <App />,
    document.querySelector('my-app')
);
export const countries = [
    'Albania',
    'Andorra',
    'Armenia',
    'Austria',
    'Azerbaijan',
    'Belarus',
    'Belgium',
    'Bosnia & Herzegovina',
    'Bulgaria',
    'Croatia',
    'Cyprus',
    'Czech Republic',
    'Denmark',
    'Estonia',
    'Finland',
    'France',
    'Georgia',
    'Germany',
    'Greece',
    'Hungary',
    'Iceland',
    'Ireland',
    'Italy',
    'Kosovo',
    'Latvia',
    'Liechtenstein',
    'Lithuania',
    'Luxembourg',
    'Macedonia',
    'Malta',
    'Moldova',
    'Monaco',
    'Montenegro',
    'Netherlands',
    'Norway',
    'Poland',
    'Portugal',
    'Romania',
    'Russia',
    'San Marino',
    'Serbia',
    'Slovakia',
    'Slovenia',
    'Spain',
    'Sweden',
    'Switzerland',
    'Turkey',
    'Ukraine',
    'United Kingdom',
    'Vatican City'
];

Combining HTML and Native Elements

You can use the KendoReact form components together with native HTML form elements for achieving complex and styled forms. For more information on appearance options, refer to the article on styling of forms.

The following example demonstrates how to apply native HTML form elements to KendoReact components.

import * as React from 'react';
import * as ReactDOM from 'react-dom';

import { NumericTextBox } from '@progress/kendo-react-inputs';
import { Button } from '@progress/kendo-react-buttons';

class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            success: false
        };
    }
    render() {
        return (
            <div className="row example-wrapper">
                <div className="col-xs-12 col-sm-6 offset-sm-3 example-col">
                    <div className="card">
                        <div className="card-block">
                            <form className="k-form" onSubmit={this.handleSubmit}>
                                <fieldset>
                                    <legend>Your Form:</legend>
                                    <label className="k-form-field">
                                        <span>First Name</span>
                                        <input
                                            name="first-name"
                                            className="k-textbox"
                                            required={true}
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Last Name</span>
                                        <input
                                            name="last-name"
                                            className="k-textbox"
                                            required={true}
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Age</span>
                                        <NumericTextBox
                                            name="age"
                                            width={"100%"}
                                            format="n0"
                                            min={0}
                                            required={true}
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Email</span>
                                        <input
                                            name="email"
                                            type="email"
                                            className="k-textbox"
                                            required={true}
                                        />
                                    </label>
                                </fieldset>
                                <Button type="submit" primary={true}>Submit</Button>
                            </form>
                        </div>
                    </div>
                </div>
                {this.state.success && (
                    <div
                        className="alert alert-success"
                        style={{ position: 'absolute' }}
                    >
                        Form submitted!
                    </div>)}
            </div>
        );
    }

    handleSubmit = (event) => {
        event.preventDefault();
        this.setState({ success: true });
        setTimeout(() => { this.setState({ success: false }); }, 3000);
    }
}

ReactDOM.render(
    <App />,
    document.querySelector('my-app')
);

Delaying Validity Styles

The form components enable you to toggle the visual representation of their invalid state and delay the application of the validity styles by passing the validityStyles property.

The following example demonstrates how to hide the visual representation of the invalid state until the first user interaction.

import * as React from 'react';
import * as ReactDOM from 'react-dom';

import { NumericTextBox, Input } from '@progress/kendo-react-inputs';
import { AutoComplete } from '@progress/kendo-react-dropdowns';
import { Button } from '@progress/kendo-react-buttons';

import { countries } from './countries';

class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            firstName: { value: '', touched: false },
            lastName: { value: '', touched: false },
            country: { value: '', touched: false },
            age: { value: null, touched: false },
            email: { value: '', touched: false },
            success: false
        };
    }
    render() {
        return (
            <div className="row example-wrapper">
                <div className="col-xs-12 col-sm-6 offset-sm-3 example-col">
                    <div className="card">
                        <div className="card-block">
                            <form className="k-form" onSubmit={this.handleSubmit}>
                                <fieldset>
                                    <legend>Your Form:</legend>
                                    <label className="k-form-field">
                                        <span>First Name</span>
                                        <Input
                                            name="firstName"
                                            value={this.state.firstName.value}
                                            validityStyles={this.state.firstName.touched}
                                            onChange={this.handleChange}
                                            required={true}
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Last Name</span>
                                        <Input
                                            name="lastName"
                                            value={this.state.lastName.value}
                                            validityStyles={this.state.lastName.touched}
                                            onChange={this.handleChange}
                                            required={true}
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Country</span>
                                        <AutoComplete
                                            name="country"
                                            value={this.state.country.value}
                                            validityStyles={this.state.country.touched}
                                            onChange={this.handleChange}
                                            style={{ width: '100%' }}
                                            data={countries}
                                            required={true}
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Age</span>
                                        <NumericTextBox
                                            name="age"
                                            value={this.state.age.value}
                                            validityStyles={this.state.age.touched}
                                            onChange={this.handleChange}
                                            width={"100%"}
                                            format="n0"
                                            min={0}
                                            required={true}
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Email</span>
                                        <Input
                                            name="email"
                                            value={this.state.email.value}
                                            validityStyles={this.state.email.touched}
                                            onChange={this.handleChange}
                                            type="email"
                                            className="k-textbox"
                                            required={true}
                                        />
                                    </label>
                                </fieldset>
                                <Button type="submit" primary={true}>Submit</Button>
                            </form>
                        </div>
                    </div>
                </div>
                {this.state.success && (
                    <div
                        className="alert alert-success"
                        style={{ position: 'absolute' }}
                    >
                        Form submitted!
                    </div>)}
            </div>
        );
    }

    handleChange = (event) => {
        this.setState({
            [event.target.name]: { value: event.target.value, touched: true }
        });
    }

    handleSubmit = (event) => {
        event.preventDefault();
        this.setState({ success: true });
        setTimeout(() => { this.setState({ success: false }); }, 3000);
    }
}

ReactDOM.render(
    <App />,
    document.querySelector('my-app')
);
export const countries = [
    'Albania',
    'Andorra',
    'Armenia',
    'Austria',
    'Azerbaijan',
    'Belarus',
    'Belgium',
    'Bosnia & Herzegovina',
    'Bulgaria',
    'Croatia',
    'Cyprus',
    'Czech Republic',
    'Denmark',
    'Estonia',
    'Finland',
    'France',
    'Georgia',
    'Germany',
    'Greece',
    'Hungary',
    'Iceland',
    'Ireland',
    'Italy',
    'Kosovo',
    'Latvia',
    'Liechtenstein',
    'Lithuania',
    'Luxembourg',
    'Macedonia',
    'Malta',
    'Moldova',
    'Monaco',
    'Montenegro',
    'Netherlands',
    'Norway',
    'Poland',
    'Portugal',
    'Romania',
    'Russia',
    'San Marino',
    'Serbia',
    'Slovakia',
    'Slovenia',
    'Spain',
    'Sweden',
    'Switzerland',
    'Turkey',
    'Ukraine',
    'United Kingdom',
    'Vatican City'
];

Applying Complex Form Validation

You can control the validity state of all form components through the valid property and provide complex form validation that is intended for a specific project. In combination with the validityStyles and validationMessage properties, valid enables you to apply input validation that is based on values which are external for the particular component.

The following example demonstrates how to achieve the complex form validation in KendoReact.

import * as React from 'react';
import * as ReactDOM from 'react-dom';

import { Input, Switch } from '@progress/kendo-react-inputs';
import { AutoComplete } from '@progress/kendo-react-dropdowns';
import { Button } from '@progress/kendo-react-buttons';

import { countries } from './countries';

class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            firstName: { value: '', touched: false },
            lastName: { value: '', touched: false },
            gender: { value: null, touched: false },
            email: { value: '', touched: false },
            username: { value: '', touched: false },
            password: { value: '', touched: false },
            confirmPassword: { value: '', touched: false },
            success: false
        };
    }
    render() {
        return (
            <div className="row example-wrapper">
                <div className="col-xs-12 col-sm-6 offset-sm-3 example-col">
                    <div className="card">
                        <div className="card-block">
                            <form className="k-form" onSubmit={this.handleSubmit}>
                                <fieldset>
                                    <legend>User Details</legend>

                                    <label className="k-form-field">
                                        <span>First Name</span>
                                        <Input
                                            name="firstName"
                                            value={this.state.firstName.value}
                                            validityStyles={this.state.firstName.touched}
                                            onChange={this.handleChange}
                                            placeholder="Your Name"
                                            pattern={"[A-za-z]+"}
                                            required={true}
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Last Name</span>
                                        <Input
                                            name="lastName"
                                            value={this.state.lastName.value}
                                            validityStyles={this.state.lastName.touched}
                                            onChange={this.handleChange}
                                            placeholder="Your Last Name"
                                            pattern={"[A-za-z]+"}
                                            required={true}
                                        />
                                    </label>
                                    <div className="k-form-field">
                                        <span>Gender</span>

                                        <input
                                            type="radio"
                                            name="gender"
                                            value="female"
                                            id="female"
                                            className="k-radio"
                                            checked={this.state.gender.value === 'female'}
                                            onChange={this.handleChange}
                                        />
                                        <label className="k-radio-label" for="female">Female</label>

                                        <input
                                            type="radio"
                                            name="gender"
                                            value="male"
                                            id="male"
                                            className="k-radio"
                                            checked={this.state.gender.value === 'male'}
                                            onChange={this.handleChange}
                                        />
                                        <label className="k-radio-label" for="male">Male</label>

                                        <input
                                            type="radio"
                                            name="gender"
                                            value="other"
                                            id="other"
                                            className="k-radio"
                                            checked={this.state.gender.value !== null && this.state.gender.value !== 'male' && this.state.gender.value !== 'female'}
                                            onChange={this.handleChange}
                                        />
                                        <label className="k-radio-label" for="other">Other</label>

                                        {this.state.gender.value !== null && this.state.gender.value !== 'male' && this.state.gender.value !== 'female' && (
                                            <label className="k-form-field mt-2 mb-2">
                                                <span>Please Specify<span className="k-required">*</span></span>
                                                <Input
                                                    name="gender"
                                                    value={this.state.gender.value === 'other' ? '' : this.state.gender.value}
                                                    validityStyles={this.state.gender.touched}
                                                    onChange={this.handleChange}
                                                    required={true}
                                                />
                                            </label>
                                        )}
                                    </div>
                                    <label className="k-form-field">
                                        <span>Email <span className="k-required">*</span></span>
                                        <Input
                                            name="email"
                                            value={this.state.email.value}
                                            validityStyles={this.state.email.touched}
                                            onChange={this.handleChange}
                                            type="email"
                                            placeholder="Your Email"
                                            required={true}
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Country<span className="k-field-info">optional</span></span>
                                        <AutoComplete style={{ width: '100%' }} name="country" data={countries} />
                                    </label>
                                </fieldset>

                                <fieldset>
                                    <legend>Credentials</legend>
                                    <label className="k-form-field">
                                        <span>Username</span>
                                        <Input
                                            name="username"
                                            value={this.state.username.value}
                                            validityStyles={this.state.username.touched}
                                            onChange={this.handleChange}
                                            placeholder="Your username"
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Password</span>
                                        <Input
                                            name="password"
                                            type="password"
                                            value={this.state.password.value}
                                            validityStyles={this.state.password.touched}
                                            onChange={this.handleChange}
                                            placeholder="Your password"
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Confirm Password</span>
                                        <Input
                                            name="confirmPassword"
                                            type="password"
                                            value={this.state.confirmPassword.value}
                                            validityStyles={this.state.confirmPassword.touched}
                                            onChange={this.handleChange}
                                            placeholder="Confirm Password"
                                        />
                                    </label>
                                    <label className="k-form-field">
                                        <span>Enable two-factor authentication</span>
                                        <Switch />
                                    </label>
                                </fieldset>

                                <div className="text-right">
                                    <Button>Cancel</Button> &nbsp;
                                    <Button primary={true}>Submit</Button>
                                </div>
                            </form>
                            {this.state.success && (
                                <div
                                    className="alert alert-success"
                                    style={{ position: 'absolute' }}
                                >
                                    Form submitted!
                                </div>)}
                        </div>
                    </div>
                </div>
            </div>
        );
    }

    handleChange = (event) => {
        this.setState({
            [event.target.name]: {
                value: event.target.value,
                touched: event.target.type !== 'radio'
            }
        });
    }

    handleSubmit = (event) => {
        event.preventDefault();
        this.setState({ success: true });
        setTimeout(() => { this.setState({ success: false }); }, 3000);
    }
}
ReactDOM.render(
    <App />,
    document.querySelector('my-app')
);
export const countries = [
    'Albania',
    'Andorra',
    'Armenia',
    'Austria',
    'Azerbaijan',
    'Belarus',
    'Belgium',
    'Bosnia & Herzegovina',
    'Bulgaria',
    'Croatia',
    'Cyprus',
    'Czech Republic',
    'Denmark',
    'Estonia',
    'Finland',
    'France',
    'Georgia',
    'Germany',
    'Greece',
    'Hungary',
    'Iceland',
    'Ireland',
    'Italy',
    'Kosovo',
    'Latvia',
    'Liechtenstein',
    'Lithuania',
    'Luxembourg',
    'Macedonia',
    'Malta',
    'Moldova',
    'Monaco',
    'Montenegro',
    'Netherlands',
    'Norway',
    'Poland',
    'Portugal',
    'Romania',
    'Russia',
    'San Marino',
    'Serbia',
    'Slovakia',
    'Slovenia',
    'Spain',
    'Sweden',
    'Switzerland',
    'Turkey',
    'Ukraine',
    'United Kingdom',
    'Vatican City'
];

In this article