Form Validation with Semantic-UI-React Form Validation with Semantic-UI-React reactjs reactjs

Form Validation with Semantic-UI-React


For the most part, you have to validate forms by hand. However, RSUI includes a couple of tools to make things a bit easier, in particular the error prop on <Form> and <Form.Input>

Here's an example of a form I put together recently. It could use a bit of refactoring, but it basically works by tying each input to state with an onChange() function, and passing a callback to the submit function which controls the visibility of the loading screen and the "Success. Thank you for submitting" portion of the form.

export default class MeetingFormModal extends Component {  constructor(props) {    super(props)    this.state = {      firstName: '',      lastName: '',      email: '',      location: '',      firstNameError: false,      lastNameError: false,      emailError: false,      locationError: false,      formError: false,      errorMessage: 'Please complete all required fields.',      complete: false,      modalOpen: false    }    this.submitMeetingForm = this.submitMeetingForm.bind(this);    this.successCallback = this.successCallback.bind(this);  }  successCallback() {    this.setState({      complete: true    })    setTimeout( () => {this.setState({modalOpen: false})}, 5000);    this.props.hideLoading();  }  handleClose = () => this.setState({ modalOpen: false })  handleOpen = () => this.setState({ modalOpen: true })  submitMeetingForm() {    let error = false;    if (this.state.studentFirstName === '') {      this.setState({firstNameError: true})      error = true    } else {      this.setState({firstNameError: false})      error = false    }    if (this.state.studentLastName === '') {      this.setState({lastNameError: true})      error = true    } else {      this.setState({lastNameError: false})      error = false    }    if (this.state.email === '') {      this.setState({emailError: true})      error = true    } else {      this.setState({emailError: false})      error = false    }    if (this.state.location === '') {      this.setState({locationError: true})      error = true    } else {      this.setState({locationError: false})      error = false    }    if (error) {      this.setState({formError: true})      return    } else {      this.setState({formError: false})    }    let meeting = {      first_name: this.state.firstName,      last_name: this.state.lastName,      email: this.state.email,      location: this.state.location,    this.props.createMeeting(meeting, this.successCallback)    this.props.showLoading();  }  capitalize(string) {    return string.charAt(0).toUpperCase() + string.slice(1);  }  render() {    return(      <Modal        trigger={<Button onClick={this.handleOpen} basic color='blue'>Schedule Now</Button>}        open={this.state.modalOpen}        onClose={this.handleClose}        closeIcon={true}      >        <Modal.Header>Schedule Your Interview</Modal.Header>        <Modal.Content>          {!this.state.complete ?          <Modal.Description>            <Form error={this.state.formError}>              <Form.Group widths='equal'>                <Form.Field>                  <Form.Input required={true} onChange={(e) => this.setState({firstName: e.target.value})} label='First Name' placeholder="First Name..." error={this.state.firstNameError}/>                </Form.Field>                <Form.Field>                  <Form.Input required={true} onChange={(e) => this.setState({lastName: e.target.value})} label='Last Name' placeholder="Last Name..." error={this.state.lastNameError}/>                </Form.Field>              </Form.Group>              <Form.Field >                <Form.Input required={true} onChange={(e) => this.setState({email: e.target.value})} label='Email' placeholder="Email..." error={this.state.emailError}/>              </Form.Field>              <Form.Field>                <Form.Input required={true} onChange={(e) => this.setState({location: e.target.value})} label='Location' placeholder='City, State/Province, Country...' error={this.state.locationError}/>              </Form.Field>            </Form>          </Modal.Description>          :             <div className='modal-complete'>              <Image src='/images/check.png' />              <p>Thanks for scheduling a meeting, {this.capitalize(this.state.name)}. We've received your information and we'll be in touch shortly.</p>            </div>          }        </Modal.Content>        {!this.state.complete ?        <Modal.Actions>          <Button color='red' onClick={this.handleClose}>Close</Button>          <Button positive icon='checkmark' labelPosition='right' content="Submit" onClick={this.submitMeetingForm} />        </Modal.Actions>        : null }      </Modal>    )  }}

Hope that helps!


We even have a better option, though not provided by semantic-ui-react -> Formik + yup
Formik: helps in managing form stateYup: 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.


Do I instead need to validate each field by hand in the handleSubmit function?

Sad, but true. SUIR doesn't have form validation at now. However, you can use HOC to work with forms like redux-form.