skip to Main Content

so I’m creating a multi-step-form using shadcn, react-hook-form and nextjs. How can I disable the next button if the user didn’t complete the first part of the form?

what I did here is, I created a two button that will increment and decrement.

  const [currentFormPage, setCurrentFormPage] = useState(1);

  const goToNextPage = () => {
    if (currentFormPage !== 3) {
      setCurrentFormPage(currentFormPage + 1);
    }
  };

  const goToPreviewsPage = () => {
    if (currentFormPage != 1) {
      setCurrentFormPage(currentFormPage - 1);
    }
  };

The next thing I did here is I created a logic that will change the form according to the currentPage.

   {
  currentFormPage === 1 && (
      <DialogHeader>
        <DialogTitle>General Information</DialogTitle>
      </DialogHeader>
      <FormField
        control={form.control}
        name="title"
        render={({ field }) => (
          <FormItem>
            <FormLabel>Title</FormLabel>
            <FormControl>
              <Input placeholder="title of event" {...field} />
            </FormControl>
            <FormMessage />
          </FormItem>
        )}
      />

      <FormField
        control={form.control}
        name="email"
        render={({ field }) => (
          <FormItem>
            <FormLabel>Email</FormLabel>
            <FormControl>
              <Input placeholder="email" {...field} />
            </FormControl>
            <FormMessage />
          </FormItem>
        )}
      />

      <FormField
        control={form.control}
        name="fullName"
        render={({ field }) => (
          <FormItem>
            <FormLabel>Full Name</FormLabel>
            <FormControl>
              <Input placeholder="Full name" {...field} />
            </FormControl>
            <FormMessage />
          </FormItem>
        )}
      />
 );
}


{
  currentFormPage === 2 && (
    <DialogHeader>
      <DialogTitle>Additional Information</DialogTitle>
    </DialogHeader>
  );
}

{
  currentFormPage === 3 && (
    <DialogHeader>
      <DialogTitle>Additional Information</DialogTitle>
    </DialogHeader>
  );
}


<DialogFooter>
  <Button variant="outline" onClick={goToPreviewsPage}>
    Back
  </Button>
  <Button variant="outline" onClick={goToNextPage}>
    Next
  </Button>
</DialogFooter>;

Now the problem I’m encountering here is, I can still press the next button, even though I didn’t complete the first form.

2

Answers


  1. You can detect that using states. put each of the forms of different pages into states and based on that you can disable or enable the next button.

    declaring state to hold the form values of each page:

    const [formValues, setFormValues] = useState({
      title: '',
      email: '',
      fullName: '',
    });
    

    then declare a function to handle each field changes:

    const handleFormFieldChange = (name, value) => {
      setFormValues({
        ...formValues,
        [name]: value,
      });
    };
    

    create another function to get all the fields of the form of the current page:

    const getCurrentPageFields = () => {
      switch (currentFormPage) {
        case 1:
          return formValues;
        case 2:
          return formValues_of_p2
          ....
        default:
          return {};
      }
    };
    

    Another function to check each of the form fields of current page and update the type of the next button:

    const isNextButtonDisabled = () => {
      const currentPageFields = getCurrentPageFields(); 
      return Object.values(currentPageFields).some(value => value === '');
    };
    

    now, your form field comps will look like this:

    <FormField
      control={form.control}
      name="title"
      render={({ field }) => (
        <FormItem>
          <FormLabel>Title</FormLabel>
          <FormControl>
            <Input
              placeholder="title of event"
              value={formValues.title}
              onChange={(e) => handleFormFieldChange('title', e.target.value)}
              {...field}
            />
          </FormControl>
          <FormMessage />
        </FormItem>
      )}
    />
    

    Finally, the next button will be:

    <Button variant="outline" onClick={goToNextPage} disabled={isNextButtonDisabled()}>
      Next
    </Button>
    
    Login or Signup to reply.
  2. To disable the next button until the user completes the first part of the form, you can add a condition to check if the required fields in the first part are filled before allowing the user to proceed to the next step. You can achieve this by utilizing the state to track the completion status of the first part of the form. Here’s how you can do it:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>
    import { useState } from 'react';
    import { useForm } from 'react-hook-form';
    
    function YourFormComponent() {
      const [currentFormPage, setCurrentFormPage] = useState(1);
      const [isFirstPartCompleted, setIsFirstPartCompleted] = useState(false); // Track completion status
    
      const goToNextPage = () => {
        if (currentFormPage !== 3 && isFirstPartCompleted) { // Check if first part is completed
          setCurrentFormPage(currentFormPage + 1);
        }
      };
    
      const goToPreviewsPage = () => {
        if (currentFormPage !== 1) {
          setCurrentFormPage(currentFormPage - 1);
        }
      };
    
      const onSubmitFirstPage = (data) => {
        // Perform validation or any other logic to determine if the first part is completed
        if (data.title && data.email && data.fullName) {
          setIsFirstPartCompleted(true);
        }
      };
    
      return (
        <form onSubmit={form.handleSubmit(onSubmitFirstPage)}>
          {currentFormPage === 1 && (
            <>
              <DialogHeader>
                <DialogTitle>General Information</DialogTitle>
              </DialogHeader>
              <FormField
                control={form.control}
                name="title"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Title</FormLabel>
                    <FormControl>
                      <Input placeholder="title of event" {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
    
              <FormField
                control={form.control}
                name="email"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Email</FormLabel>
                    <FormControl>
                      <Input placeholder="email" {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
    
              <FormField
                control={form.control}
                name="fullName"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Full Name</FormLabel>
                    <FormControl>
                      <Input placeholder="Full name" {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
    
              <DialogFooter>
                <Button variant="outline" onClick={goToPreviewsPage}>
                  Back
                </Button>
                <Button type="submit" variant="outline">
                  Next
                </Button>
              </DialogFooter>
            </>
          )}
    
          {/* Render other form steps similarly */}
        </form>
      );
    }
    
    export default YourFormComponent;

    In this code:

    A state variable isFirstPartCompleted is added to track whether the required fields in the first part of the form are filled.
    An onSubmitFirstPage function is included to execute when the user submits the first part of the form. Within this function, validation occurs to ensure the required fields are filled. If validation passes, isFirstPartCompleted is set to true.
    Within the goToNextPage function, a condition is added to verify if isFirstPartCompleted is true before permitting the user to proceed to the next step. If isFirstPartCompleted is false, the user cannot proceed until the first part is completed.

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