Search code examples
reactjsformsreact-bootstrapreact-bootstrap-form

Check if React Bootstrap Form is filled in or not to conditionally disable submit button


We have the following contact form in React using https://react-bootstrap.github.io/forms/overview/

let contactForm =
    (<Form ref={formRef} onSubmit={sendEmail} className='toggle-contact-form'>
        <div className='toggle-contact-form__header'>
            <p className='p1'>Please Reach out!</p>
            <p className='p2'>Use our contact form to reach out with any questions, concerns or issues with the website.</p>
        </div>

        <Form.Row style={{ paddingTop: 20 }}>
            <Form.Group as={Col} controlId='name'>
                <Form.Label>Name</Form.Label>
                <Form.Control className='cbb-home-input' placeholder='required' />
            </Form.Group>
        </Form.Row>

        <Form.Row>
            <Form.Group as={Col} controlId='email'>
                <Form.Label>Email Address</Form.Label>
                <Form.Control className='cbb-home-input' type='email' placeholder='required' />
            </Form.Group>
        </Form.Row>

        <Form.Row>
            <Form.Group as={Col} controlId='phone'>
                <Form.Label>Phone Number</Form.Label>
                <Form.Control className='cbb-home-input' placeholder='optional' />
            </Form.Group>
        </Form.Row>

        <Form.Row>
            <Form.Group as={Col} controlId='message'>
                <Form.Label>Message</Form.Label>
                <Form.Control className='cbb-home-input' as='textarea' rows='2' placeholder='required' />
            </Form.Group>
        </Form.Row>

        <Form.Row>
            <Form.Group as={Col} controlId='button'>
                <Button variant='primary' type='submit' disabled={true}>
                    {isSubmitting ? 'Sending Email...' : 'Submit'}
                </Button>
            </Form.Group>
        </Form.Row>
    </Form>);

Currently the button disabled={true}, we'd like to make this conditional on the Form.Control elements for name, message both being not empty, and email being a valid email address. Currently we have no form validation. Is it possible to validate this form as such?


Solution

  • The Bootstrap docs suggest using a library to make this process easier:

    It's often beneficial (especially in React) to handle form validation via a library like Formik, or react-formal. In those cases, isValid and isInvalid props can be added to form controls to manually apply validation styles.

    But here's how you can do it without a library:

    Since we need access to the values of the input fields, we'll need to use controlled components to hold the form data. First we will set up some useState variables to hold the data:

      const [name, setName] = useState("");
      const [message, setMessage] = useState("");
      const [email, setEmail] = useState("");
    

    Then we need to use those state variables to handle the data in form fields by setting the value and onChange props:

    ...
    
    <Form.Control
    value={name}
    onChange={(e) => {
      setName(e.target.value);
    }}
    className="cbb-home-input"
    placeholder="required"
    />
    
    ...
    
    <Form.Control
      value={email}
      onChange={(e) => {
        setEmail(e.target.value);
      }}
      className="cbb-home-input"
      type="email"
      placeholder="required"
    />
    
    ...
    
    <Form.Control
      value={message}
      onChange={(e) => {
        setMessage(e.target.value);
      }}
      className="cbb-home-input"
      as="textarea"
      rows="2"
      placeholder="required"
    />
    
    ...
    

    Now that we have access to the form field data, we can create a variable to keep track of whether the user input is valid:

    const isValid = checkValidity(name, message, email);
    

    The checkValidity function can check if name, message, and email meet the requirements we want them too:

    const checkEmail = (email) => {
      return /^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/.test(email);
    };
    
    const checkValidity = (name, message, email) => {
      return !!name && !!message && checkEmail(email);
    };
    

    At this point, the isValid variable will always be updated with whether or not the current user input in the form is valid. Specifically, we are making sure name and message are not empty, and that email passes a simple regex validity check.

    Finally, we disable the submit button whenever isValid is false using the disabled prop:

    <Button variant="primary" type="submit" disabled={!isValid}>
       {isSubmitting ? "Sending Email..." : "Submit"}
    </Button>
    

    Here's a full working example on CodeSandbox: Edit Form Validity Check