Every Flutter developer has written this code a hundred times:
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
Controllers. Dispose. Validators. setState. Error text. For every. Single. Form.
I built form_forge to make this go away forever.
What It Does
You write this:
@FormForge()
class LoginForm {
@IsRequired()
@IsEmail()
late final String email;
@IsRequired()
@MinLength(8)
late final String password;
}
Run dart run build_runner build.
You get:
-
LoginFormController— typed fields, validation, submission handling -
LoginFormWidget— drop-in widget with error display -
LoginFormData— typed data for your submit callback
12 lines. Not 87.
The Cool Parts
Cross-field validation in one line:
@MustMatch('password', message: 'Passwords do not match')
late final String confirmPassword;
Async validation (check email uniqueness):
@AsyncValidate()
late final String email;
// Register at runtime:
controller.registerAsyncValidator('email', (value) async {
return await api.emailExists(value) ? 'Already taken' : null;
});
Auto widget mapping:
-
String→ TextFormField -
int→ TextFormField with number keyboard -
bool→ CheckboxListTile
Works with any state management — Provider, Riverpod, Bloc, or vanilla setState.
Install
dependencies:
form_forge: ^0.1.0
dev_dependencies:
form_forge_generator: ^0.1.0
build_runner: ^2.4.0
Links
It's v0.1.0 — stars and feedback welcome!
Top comments (0)