Skip to content

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.

Decision

Situation Use Partial Validation Why
Multi-step "Previous" button Yes Don't validate when going back
"Save draft" vs "Publish" Yes Draft needs no validation
Progressive disclosure Yes Only validate visible sections
Simple single-step forms No Not needed
All fields always required No Full validation appropriate

Pattern

// Multi-step form: Previous button (no validation)
$form['actions']['previous'] = [
  '#type' => 'submit',
  '#value' => $this->t('Previous'),
  '#limit_validation_errors' => [], // No validation
  '#submit' => ['::previousSubmit'],
];

// Multi-step form: Next button (validate current step only)
$form['actions']['next'] = [
  '#type' => 'submit',
  '#value' => $this->t('Next'),
  '#limit_validation_errors' => [['step1']], // Only validate step1
  '#submit' => ['::nextSubmit'],
];

// Save draft (no validation) vs Publish (full validation)
$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'],
];

Syntax

// 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' => []

How It Works

FormValidator checks button #limit_validation_errors. If present, only validates specified element paths. If absent, validates entire form. #required still enforced on specified paths.

Common Mistakes

  • Wrong: '#limit_validation_errors' => 'field_name' (string) → Right: [['field_name']] (array of arrays)
  • Wrong: Missing parent elements in path → Right: Include full path [['container', 'field']]
  • Wrong: Partial validation without #submit handler → Right: Always pair with #submit
  • Wrong: Wrong element path → Right: Match form structure exactly

See Also