skip to Main Content

I have a form in a React app. I am using the useActionState hook to manage form status. How can I set the submit button to disabled until the user enters something in the text input?

By using the useState hook to store the input and calling the setter method on input change I can track if there is an input in the form field. But by using useActionState I can only know the form values after submitting the form.

import { useActionState, useState } from "react";

export function MyForm() {

  // form state managed with useActionState
  const [state, formAction] = useActionState(
    updateState,
    { name: ""}
  )
  function updateState(_prevState, formData) {
    // do something
    return {name: formData.get("name") as string}
  }

  // form state managed with useState
  const [state2, setState2] = useState({name: ""})
  function handleChange(e) {
    setState2({name: e.target.value})
  }
  function handleSubmit(e) {
    e.preventDefault()
    // do something
    setState2({name: ""})
  }

  return (
    <>
      {/* form state managed with useActionState */}
      <form  action={formAction}>
        <input type="text" name="name" />
        <button type="submit">Submit</button> {/* <- I want this to be disabled until user enters a value */}
        <div>{state.name}</div>
      </form>

      {/* form state managed with useState */}
      <form onSubmit={handleSubmit}>
        <input type="text" name="name" onChange={handleChange} value={state2.name}/>
        <button disabled={state2.name ? false : true} type="submit">Submit</button> 
        <div>{state2.name}</div>
      </form>
    </>
  )
}

I know there is a hook useFormStatus which might be used for this but I don’t like the idea of having the content of my form in a separate child component.

2

Answers


  1. Both useActionState and useFormStatus hooks gives you some ways to use state of a form after submission. none of them will give you ability to work with states before a form submission. So, if you want to disable your button if an input is empty, you need to use useState to check for input’s value and disable button on any change. For example:

    import { useActionState, useState } from "react";
    
    export function MyForm() {
    
      // form state managed with useActionState
      const [state, formAction] = useActionState(
        updateState,
        { name: ""}
      )
      function updateState(_prevState, formData) {
        // do something
        return {name: formData.get("name") as string}
      }
    
      // form state managed with useState
      const [inputValue, setInputValue] = useState(null)
      function handleChange(e) {
        setInputValue(e.currentTarget.value)
      }
    
      return (
          <form action={formAction}>
            <input type="text" name="name" onChange={handleChange} />
            <button type="submit" disabled={!inputValue}>Submit</button>
            <div>{state.name}</div>
          </form>
      )
    }
    
    Login or Signup to reply.
  2. import { useActionState, useState } from "react";
    
    export function MyForm() {
      const [formData, setFormData] = useState({ name: "" });
    
      const handleChange = (event) => {
        setFormData({ ...formData, [event.target.name]: event.target.value });
      };
    
      const isFormEmpty = Object.values(formData).every((value) => value === "");
    
      const [state, formAction] = useActionState(
        updateState,
        { name: "" }
      );
    
      function updateState(_prevState, formData) {
        console.log("Submitted data:", formData);
        return formData;
      }
    
      const handleSubmit = (event) => {
        event.preventDefault();
        if (!isFormEmpty) {
          formAction(formData);
        } else {
          console.warn("Form is empty. Please fill in the required fields.");
        }
      };
    
      return (
        <>
          <form onSubmit={handleSubmit}>
            <input
              type="text"
              name="name"
              value={formData.name}
              onChange={handleChange}
            />
            <button type="submit" disabled={isFormEmpty}>
              Submit
            </button>
            <div>{formData.name}</div>
          </form>
        </>
      );
    }
    

    This code implements a form with a submit button that is disabled until the user enters a value in the input field. It uses the useState hook to manage the form state and the isFormEmpty function to determine if the form is empty. The handleSubmit function is triggered when the form is submitted, and it conditionally submits the form data using the formAction function from useActionState or logs a warning message if the form is empty.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search