Form validation is a common requirement in almost every app. Using Bloc (or Cubit) for form validation gives you a reactive, testable, and maintainable approach. This guide covers everything from basic field validation to complex multi‑step forms with asynchronous validation and submission handling.
Why Use Bloc for Form Validation?
- Reactive UI – The UI automatically updates when validation state changes.
- Separation of concerns – Validation logic lives in the bloc/cubit, not scattered in widgets.
- Testability – You can unit‑test validation rules without building widgets.
- Centralised state – Form state (validity, submission status) is managed in one place.
- Consistency – Same validation rules apply everywhere, preventing duplication.
Basic Form Validation with Cubit
For simple forms, Cubit is often enough. Let's build a login form with email and password validation, and a submit button that is enabled only when the form is valid.
Using Bloc for Complex Forms
For larger forms with many fields or complex validation (e.g., cross‑field validation), using Bloc with events gives you more structure and traceability. Let's build a registration form with username, email, password, and password confirmation.
Use BlocConsumer to handle both UI rebuilds and side effects (navigation, snackbars).
Asynchronous Validation
Sometimes you need to validate against a server (e.g., check if username is already taken). This requires async validation, which you can handle inside the bloc with debouncing.
Best Practices
- Separate validation functions – Keep validation logic in pure functions for easy testing.
- Use
copyWithto update state immutably – Ensures predictable state changes. - Leverage
Equatable– Prevents unnecessary rebuilds when state doesn't change. - Debounce async validation – Use event transformers to avoid excessive API calls.
- Show loading indicators – Provide visual feedback during submission and async validation.
- Disable submit button while submitting – Prevents multiple submissions.
- Handle submission errors gracefully – Show user-friendly error messages.
Common Mistakes
- ❌ Putting validation logic directly in the UI – Leads to code duplication and makes testing hard.
- ❌ Not resetting error messages – Errors can persist after the user fixes the field if not cleared.
- ❌ Re‑evaluating validation on every keystroke without debouncing async validations – Causes unnecessary network calls.
- ❌ Not handling focus and cursor position – When rebuilding the entire form, focus may be lost. Use
AutovalidateModecarefully. - ❌ Ignoring form submission state – Users need to know if the form is processing.
What's Next?
Now that you can handle forms, explore how to structure larger apps with modular architecture and how to test your blocs.
Next, explore Bloc testing and Bloc architecture.