Validation: Partial Validation Pattern
When to Use
Use partial validation for multi-step forms with "Previous" buttons, "Save draft" vs "Publish" buttons, or progressive disclosure forms.
When to Use Partial Validation:
- Multi-step forms with "Previous" button
- "Save draft" vs "Publish" buttons
- Progressive disclosure forms
- Forms with optional sections
When NOT to Use:
- Simple single-step forms
- All fields always required
- No multiple submit buttons
Pattern: #limit_validation_errors
#limit_validation_errors Property:
Applied to: Button elements (submit, button)
Effect: Only validates specified form sections
Syntax: Array of arrays (element parents)
Example - Multi-Step Form:
$form['actions']['previous'] = [
'#type' => 'submit',
'#value' => $this->t('Previous'),
'#limit_validation_errors' => [['step1']], // Only validate step1
'#submit' => ['::previousSubmit'],
];
$form['actions']['next'] = [
'#type' => 'submit',
'#value' => $this->t('Next'),
'#limit_validation_errors' => [['step2']], // Only validate step2
'#submit' => ['::nextSubmit'],
];
Example - Save Draft:
$form['actions']['draft'] = [
'#type' => 'submit',
'#value' => $this->t('Save Draft'),
'#limit_validation_errors' => [], // No validation
'#submit' => ['::saveDraft'],
];
$form['actions']['publish'] = [
'#type' => 'submit',
'#value' => $this->t('Publish'),
// No #limit_validation_errors = full validation
'#submit' => ['::publishSubmit'],
];
Reference: Syntax Details
Single Element:
'#limit_validation_errors' => [['field_name']]
Nested Element:
'#limit_validation_errors' => [['container', 'field_name']]
Multiple Elements:
'#limit_validation_errors' => [
['step1', 'name'],
['step1', 'email'],
]
No Validation:
'#limit_validation_errors' => []
Reference: How It Works
Internal Mechanism:
FormValidator checks button #limit_validation_errors
If present: Only validates specified element paths
If absent: Validates entire form
#required still enforced on specified paths
Reference: /web/core/lib/Drupal/Core/Form/FormStateInterface.php lines 461-532
Common Mistakes
Incorrect Path:
// WRONG - string instead of array
'#limit_validation_errors' => 'field_name'
// CORRECT
'#limit_validation_errors' => [['field_name']]
Missing Parent Elements:
// If field is $form['container']['field']
// WRONG
'#limit_validation_errors' => [['field']]
// CORRECT
'#limit_validation_errors' => [['container', 'field']]
Forgetting #submit Handler:
Partial validation without custom submit handler is useless
Always pair #limit_validation_errors with #submit
See Also
- Multi-Step Form Pattern (dedicated section)
- Submission Architecture (dedicated section)
- Button Elements (element reference)