Search code examples
javascriptvalidationreactjssemantic-uisemantic-ui-react

Form Validation with Semantic-UI-React


I am using the official Semantic UI React components to create a web application. I have a form on my sign up page, which contains an email field, a password field, and a confirm password field.

import {Component} from 'react';
import {Button, Form, Message} from 'semantic-ui-react';
import {signUp} from '../../actions/auth';

class SignUp extends Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleSubmit(e, {formData}) {
        e.preventDefault();

        //
        // Potentially need to manually validate fields here?
        //

        // Send a POST request to the server with the formData
        this.props.dispatch(signUp(formData)).then(({isAuthenticated}) => {
            if (isAuthenticated) {
                // Redirect to the home page if the user is authenticated
                this.props.router.push('/');
            }
        }
    }
    render() {
        const {err} = this.props;

        return (
            <Form onSubmit={this.handleSubmit} error={Boolean(err)}>
                <Form.Input label="Email" name="email" type="text"/>
                <Form.Input label="Password" name="password" type="password"/>
                <Form.Input label="Confirm Password" name="confirmPassword" type="password"/>

                {err &&
                    <Message header="Error" content={err.message} error/>
                }

                <Button size="huge" type="submit" primary>Sign Up</Button>
            </Form>
        );
    }
}

Now, I am used to the regular Semantic UI library, which has a Form Validation addon. Usually, I would define the rules like so in a separate JavaScript file

$('.ui.form').form({
    fields: {
        email: {
            identifier: 'email',
            rules: [{
                type: 'empty',
                prompt: 'Please enter your email address'
            }, {
                type: 'regExp',
                value: "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
                prompt: 'Please enter a valid email address'
            }]
        },
        password: {
            identifier: 'password',
            rules: [{
                type: 'empty',
                prompt: 'Please enter your password'
            }, {
                type: 'minLength[8]',
                prompt: 'Your password must be at least {ruleValue} characters'
            }]
        },
        confirmPassword: {
            identifier: 'confirmPassword',
            rules: [{
                type: 'match[password]',
                prompt: 'The password you provided does not match'
            }]
        }
    }
});

Is there a similar method using the Semantic UI React components for validating the form? I've searched through the documentation without any success, and there doesn't seem to be examples of validation using this Semantic UI React library.

Do I instead need to validate each field by hand in the handleSubmit function? What is the best way to fix this problem? Thanks for the help!


Solution

  • We even have a better option, though not provided by semantic-ui-react -> Formik + yup
    Formik: helps in managing form state Yup: helps in the validation of that state

    I have the below component which is basically an edit form created using semantic-ui-react.

    import React, { Component } from "react";
    import { Button, Form, Modal, Message, Divider } from "semantic-ui-react";
    import { Formik } from "formik";
    import * as yup from "yup";
    
    
    class EditAboutGrid extends Component {
    
      render() {
        const {
          userBasic,
          editBasicModal,
          closeModal
        } = this.props;
    
        return (
          <Formik
            initialValues={{
              firstName: userBasic.firstName,
              lastName: userBasic.lastName,
              bio: userBasic.bio,
            }}
            validationSchema={yup.object().shape({
              firstName: yup
                .string()
                .required("Name cannot be empty"),
              lastName: yup
                .string()
                .required("Name cannot be empty"),
              bio: yup
                .string()
                .max(1000, "Maximum characters exceed 1000")
                .nullable()
            })}
            onSubmit={(values, actions) => {
              //do your stuff here like api calls
            }}
            render={({
              values,
              errors,
              handleChange,
              handleSubmit,
              isSubmitting,
              dirty,
              setFieldValue
            }) => (
              <Modal open={editBasicModal} size="small">
                <Modal.Header>Your basic details</Modal.Header>
                <Modal.Content scrolling>
                  {errors.firstName && <Message error content={errors.firstName} />}
                  {errors.lastName && <Message error content={errors.lastName} />}
                  {errors.bio && <Message error content={errors.bio} />}
    
                  <Form loading={isSubmitting}>
                    <Form.Group inline widths="equal">
                      <Form.Input
                        required
                        label="First Name"
                        fluid
                        type="text"
                        name="firstName"
                        value={values.firstName}
                        onChange={handleChange}
                        error={errors.firstName !== undefined}
                      />
                      <Form.Input
                        required
                        label="Last Name"
                        fluid
                        type="text"
                        name="lastName"
                        value={values.lastName}
                        onChange={handleChange}
                        error={errors.lastName !== undefined}
                      />
                    </Form.Group>
                    <Form.TextArea
                      label="Bio"
                      type="text"
                      name="bio"
                      value={values.bio}
                      onChange={handleChange}
                      rows={3}
                      error={errors.bio !== undefined}
                    />
                  </Form>
                </Modal.Content>
                <Modal.Actions open={true}>
                  <Button
                    onClick={() => (dirty ? closeModal(true) : closeModal(false))}>
                    Cancel
                  </Button>
                  <Button
                    primary
                    type="submit"
                    onClick={handleSubmit}
                    loading={isSubmitting}
                    disabled={isSubmitting || !isEmpty(errors) || !dirty}>
                    Update
                  </Button>
                </Modal.Actions>
              </Modal>
            )}
          />
        );
      }
    }
    

    And this form is called using:

      <EditAboutGrid
        editBasicModal={this.state.editBasicModal}
        userBasic={this.state.user.basic}
        closeModal={this.closeModal}
      />
    

    initialValues is the place where the things start. Here you pass on the initial/default values to the inputs of your form. values(in form) will pick data value from this default.

    validationSchema is the place where all validation happens using yup

    onSubmit would be called on the form submission.

    Handling form using Formik + yup is very easy. I am loving it.