Skip to content

fabrik_forms

pub.dev

The fabrik_forms package is a clean, testable, and UI-agnostic form state management system for Flutter.

It’s designed to support both reactive patterns and integration with any state management solution like BLoC, Riverpod, or Provider.

Add the package to your pubspec.yaml:

dependencies:
fabrik_forms: ^0.1.0

Then run:

Terminal window
flutter pub get

Import fabrik_forms in your Dart files:

import 'package:fabrik_forms/fabrik_forms.dart';

Create a form with fields and validators:

final formNotifier = FabrikFormNotifier<String>(
FabrikForm({
'email': FabrikField<String>(
value: '',
validators: [EmailValidator()],
),
'password': FabrikField<String>(
value: '',
validators: [
PasswordValidator(
requireDigit: true,
requireSpecialChar: true,
),
],
),
}),
);

Wrap your UI with FabrikFormBuilder:

FabrikFormBuilder<String>(
formNotifier: formNotifier,
builder: (context, form, get) {
final email = get<String>('email');
final password = get<String>('password');
return Column(
children: [
TextFormField(
onChanged: (val) => formNotifier.update('email', val),
decoration: InputDecoration(
labelText: 'Email',
errorText: email.visibleError,
),
),
TextFormField(
onChanged: (val) => formNotifier.update('password', val),
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
errorText: password.visibleError,
),
),
ElevatedButton(
onPressed: form.isValid ? () => submit(form.values) : null,
child: const Text('Sign In'),
),
],
);
},
);

RequiredValidator(message: 'This field is required');
MinLengthValidator(min: 6, message: 'Too short');
MaxLengthValidator(max: 20, message: 'Too long');
EmailValidator(
isRequired: true,
requiredMessage: 'Required',
invalidMessage: 'Invalid email',
);
PasswordValidator(
requireDigit: true,
requireUppercase: true,
requireSpecialChar: true,
);

  • ✅ Field-level validation with reusable validators
  • ✅ Form-level state with .isValid, .isDirty, .isTouched, .values, .errors
  • ✅ Notifier-based reactivity
  • ✅ Builder widget for clean UI
  • ✅ Works with or without a widget tree
  • ✅ Fully testable without Flutter widgets