Multistep forms are a great improvement to the user experience, especially if a form has a lot of fields. Rather than users having to deal with an overly long form, you can present them with a series of steps with just a few fields on each. Most multistep forms feature a back button. The problem is, when you have required fields on a particular step, and the field is not filled in, the user will get a validation error when hitting back. This is because the Drupal form is being validated and all of the necessary validation handlers are being called and validation rules processed. Receiving a validation error when simply trying to go back on a step is not a great user experience!

But fear not. You can still have your nice multistep form and get rid of these pesky errors when hitting a back button. The problem is solved by adding the #limit_validation_errors property to the back button.

Update 11th October - The fix using #limit_validation_errors described in this post has been rolled into the Multistep Nodeform module. See the bottom of this post for more details.

In order to demonstrate, let's set up a multistep form.

Set up the multistep form

I am using the Multistep Nodeform module to create the multistep form. After you enable the Multistep Nodeform module, you will see a new field appear on the manage field screen for any content type. The new field is titled "Add new step". All you need to do is add the steps with a label for each and then drag your fields under each step.

I have configured the Article content type to be multistep. I have added two steps, Step 1 and Step 2 and dragged Title and Tags under Step 1 and Body and Image under Step 2. See below for the manage field form for the Article content type (found here: admin/structure/types/manage/article/fields):

When you add Article content, the node form will now be multi step.

Validation error on back button

If you hit the back button without filling the required body field, you will get a validation error and be prevented from going back. This is clearly a bad user experience as any user would expect to be able to go back from a step without completing it.

Solution

The solution is to limit validation on the back button and only the back button. We do not want to see validation errors if no, or invalid, data is added to a step when the user is simply going back. Fortunately, Drupal provides a Form API property for exactly this case, the #limit_validation_errors property.

In order to add the #limit_validation_errors property to the Article node form, you need to implement hook_form_alter() and add to the element for the back button. The machine name for the back button in the Multistep Nodeform module is called previous.

I have created a module called Article and my implementation of hook_form_alter is a function called article_form_alter(). You can add your hook implementation to another custom module if you prefer.

In the code snippet below, #limit_validation_errors is added to the previous element. It is assigned an empty array, which means no validation will be applied.

/** * Implements hook_form_alter. */ function article_form_alter(&$form, &$form_state, $form_id) { if ($form_id == 'article_node_form') { $form['actions']['previous']['#limit_validation_errors'] = array(); } }

This is actually not enough and a lot of people seem to be going wrong here. You must also add the #submit property to the button, like so:

/** * Implements hook_form_alter. */ function article_form_alter(&$form, &$form_state, $form_id) { if ($form_id == 'article_node_form') { $form['actions']['previous']['#submit'][] = array(); $form['actions']['previous']['#limit_validation_errors'] = array(); } }

The (API documentation)[https://api.drupal.org/api/drupal/includes%21form.inc/function/form_set_error/7] makes this clear: #limit_validation_errors does not have any effect if #submit is not set.

We don't actually need a submit handler function, so simply set an empty array.

Partial validation

You may have a need to have a mix of limited and full validation on the same step. In the example of the Article multistep form, let's say that you want to allow users to go back without entering any data in the body field, but you want to ensure they upload an image. In this case, you can add the element where the validation rules still apply to the #limit_validation_errors array. In the code snippet below, I have added field_image.

function article_form_alter(&$form, &$form_state, $form_id) { if ($form_id == 'article_node_form') { $form['actions']['previous']['#submit'][] = array(); $form['actions']['previous']['#limit_validation_errors'] = array(array('field_image')); } }

The image field needs to be made a required field for this to have any effect. Now if I hit the back button without uploading an image, I will get a validation error.

Use with caution

You should only use the #limit_validation_errors property on buttons that do not result in data being saved to the database when triggered. Do not use it on a button that results in data being saved, such as the save button, because then the data will be saved without any validation.

Wrapping up

The #limit_validation_errors is one of those little gems in the Form API that make your life as a developer a lot easier. It allows for a pragmatic approach where you might not always want to validate when a specific button is triggered. Use it with care!

The fix using #limit_validation_errors described in this post has been rolled into the Multistep Nodeform module. So you don't need to do this yourself in a form alter if you are using the Multistep Nodeform module. You may still find the problem in other multi-step modules. As mentioned in the comments below, it is recommended to raise this sort of thing as an issue in the issue queue of the module itself and contribute a patch. You may still find yourself needing to use the form alter approach technique outlined in this post (as well as contributing a patch in the issue queue) if you are under a hard deadline and don't have time to wait for the patch to be committed and don't want to have to deal with the ramifications of having a contributed module that you need to patch each time you upgrade (that problem disappears once the patch has been committed).