smart_multi_form_fields 1.3.0
smart_multi_form_fields: ^1.3.0 copied to clipboard
A single, production-grade Flutter form field widget rendering text, password, phone, OTP, date, dropdown, and file inputs via sealed configurations.
Smart Form Field (smart_multi_form_fields) #
A production-grade, type-safe Flutter form field package that provides a single public widget (SmartFormField) capable of rendering multiple input types through a sealed configuration hierarchy.
Implementation Status #
| Type | Config | Status |
|---|---|---|
| Text | SmartTextConfig |
✅ Complete |
| Password | SmartPasswordConfig |
✅ Complete |
| Phone | SmartPhoneConfig |
✅ Complete |
| OTP | SmartOtpConfig |
✅ Complete |
| Date | SmartDateConfig |
⏳ Stub |
| Dropdown | SmartDropdownConfig |
⏳ Stub |
| File | SmartFileConfig |
⏳ Stub |
Features #
- 📱 Supported Platforms: Tested and officially supported on Android & iOS.
- 🎯 Single Public Widget:
SmartFormField(config: ...)for every input type. - 🔒 Type-Safe Sealed Configs:
SmartFieldConfigis sealed — compile-time safety, zero dead properties. - 🛡️ Built-in Validation: Required check,
minLength,maxLength, custom validator chain (SmartValidators.email). - 🔑 Password Strength & Custom Scoring: Animated 4-segment strength meter, custom scoring algorithms, custom meter UI, obscuring character selection (
•,*), custom eye icons. - 🔄 Confirm Password Matching: Real-time exact string match validation via
confirmPasswordController. - ✍️ Formatting & Capitalization:
autoCapitalizeWords, custominputFormatters, auto-trimming. - 🔌 External Controller: Optional
controllerproperty — you own disposal if provided, package handles it if omitted. - 🎨 Automatic Theming: Seamlessly inherits app
InputDecorationThemeand light/darkColorScheme. - ☎️ Phone Field with Real Validation: Country-code picker with flags,
libphonenumber-derived per-country format validation, and E.164-formatted output — no manual dial-code string manipulation needed. - ⏱ Debounced & Async Search:
SmartTextConfig.search()with race-condition-safe async execution. - 🔑 Programmatic Control: Validate, reset, read values via
GlobalKey<SmartBaseShellState>. - 🔢 OTP / PIN Field: Segmented box UI, native SMS autofill, zero-touch controller-based interception support, optional PIN-style masking, auto-submit on completion — zero external dependencies.
Installation #
dependencies:
smart_multi_form_fields: ^1.3.0
Usage Examples & Previews #
import 'package:smart_multi_form_fields/smart_multi_form_fields.dart';
Section 1: Text Input (SmartTextConfig) #
SmartTextField Previews
| Basic Text & Email Validation | Bio Multiline & Character Counter |
|---|---|
![]() |
![]() |
1. Basic Text Input & Validation
SmartFormField(
config: SmartTextConfig(
label: 'Full Name',
hint: 'John Doe',
isRequired: true,
autoCapitalizeWords: true,
prefixIcon: const Icon(Icons.person),
validators: [
(value) => value!.length < 3 ? 'Name must be at least 3 characters' : null,
],
),
)
2. Email Field with Built-in Validator
SmartFormField(
config: SmartTextConfig(
label: 'Email Address',
hint: 'user@example.com',
isRequired: true,
validators: [SmartValidators.email],
prefixIcon: const Icon(Icons.email),
),
)
3. Multiline & Character Counter (Bio / Notes)
SmartFormField(
config: SmartTextConfig(
label: 'Bio',
hint: 'Write a short bio...',
minLength: 10,
maxLength: 200,
maxLines: 4,
minLines: 2,
prefixIcon: const Icon(Icons.info),
),
)
4. Auto-Clear Button & Icons
SmartFormField(
config: SmartTextConfig(
label: 'Address',
hint: 'Enter your address',
showClearButton: true, // Auto-shows (×) clear icon when non-empty
prefixIcon: const Icon(Icons.location_on),
),
)
5. Async Search Field with Debounce
SmartFormField(
config: SmartTextConfig.search(
label: 'Search Products',
hint: 'Type product name...',
debounce: const Duration(milliseconds: 400),
onSearchAsync: (query, isCurrent) async {
final results = await myApi.searchProducts(query);
if (isCurrent()) { // Ensures older, slower API responses don't overwrite newer results
setState(() => _searchResults = results);
}
},
),
)
6. External Controller & Focus Traversal
final _nameController = TextEditingController();
final _nextFocus = FocusNode();
SmartFormField(
config: SmartTextConfig(
label: 'First Name',
controller: _nameController,
nextFocusNode: _nextFocus,
textInputAction: TextInputAction.next,
),
)
// Read or pre-fill value anytime:
_nameController.text = 'Pre-filled';
7. Programmatic Validation via GlobalKey
final _formKey = GlobalKey<SmartBaseShellState>();
SmartFormField(
key: _formKey,
config: SmartTextConfig(label: 'Username', isRequired: true),
)
// On submit button click:
void onSubmit() {
final error = _formKey.currentState?.validate();
if (error == null) {
final value = _formKey.currentState?.value;
print('Valid value: $value');
}
}
Section 2: Password Input (SmartPasswordConfig) #
SmartPasswordField Previews
| Strength Meter & Custom Policy | Custom Validators & Live Values Card |
|---|---|
![]() |
![]() |
1. Password with Strength Meter
SmartFormField(
config: SmartPasswordConfig(
label: 'Password',
hint: 'Enter your password',
isRequired: true,
minPasswordLength: 8,
showStrengthMeter: true, // Animated 4-segment strength bar
),
)
2. Strict Password with Complexity Rules
SmartFormField(
config: SmartPasswordConfig(
label: 'Strong Password',
isRequired: true,
minPasswordLength: 8,
requireUppercase: true, // Must include A-Z
requireLowercase: true, // Must include a-z
requireDigit: true, // Must include 0-9
requireSpecialChar: true, // Must include !@#$%^&*
),
)
3. Confirm Password Match Validation
final _passwordController = TextEditingController();
// Original password field
SmartFormField(
config: SmartPasswordConfig(
label: 'Password',
controller: _passwordController,
isRequired: true,
),
)
// Confirm password field — compares value against original field
SmartFormField(
config: SmartPasswordConfig(
label: 'Confirm Password',
confirmPasswordController: _passwordController,
confirmMismatchMessage: 'Passwords do not match',
showStrengthMeter: false,
isRequired: true,
),
)
4. Custom Obscuring Character & Custom Toggle Icon
SmartFormField(
config: SmartPasswordConfig(
label: 'Custom Password',
obscuringCharacter: '*', // Mask symbol (* instead of default •)
toggleIconBuilder: (isObscured) => Icon(
isObscured ? Icons.lock_outline : Icons.lock_open_outlined,
color: Colors.blue,
size: 20,
),
),
)
5. Custom Strength Scorer & Custom Strength UI Builder
SmartFormField(
config: SmartPasswordConfig(
label: 'Custom Policy Password',
// Custom scoring algorithm
customStrengthScorer: (password, minLength) {
if (password.length < minLength) return PasswordStrength.weak;
if (password.contains('123456')) return PasswordStrength.weak;
return PasswordStrengthScorer.score(password, minLength: minLength);
},
// Custom strength meter UI replacement
strengthMeterBuilder: (context, strength) {
return Text('Strength: ${strength.label}', style: TextStyle(color: strength.color));
},
),
)
Section 3: Phone Input (SmartPhoneConfig) #
SmartPhoneField Previews
| Phone Field Implementation | Validation & Selection |
|---|---|
![]() |
![]() |
1. Basic Phone Field
SmartFormField(
config: SmartPhoneConfig(
label: 'Phone Number',
defaultCountryCode: 'IN', // required — pick your app's primary market
isRequired: true,
helperText: 'We\'ll text you a verification code',
),
)
2. Custom Error Message & Country Change Callback
SmartFormField(
config: SmartPhoneConfig(
label: 'Phone Number',
defaultCountryCode: 'GB',
invalidNumberMessage: 'That doesn\'t look like a valid number',
onCountryChanged: (isoCode, dialCode) {
print('User switched to $isoCode ($dialCode)');
},
),
)
3. Getting the Full E.164 Value
final _phoneKey = GlobalKey<SmartBaseShellState>();
SmartFormField(
key: _phoneKey,
config: SmartPhoneConfig(label: 'Phone', defaultCountryCode: 'US'),
)
// Always returns the full international format, e.g. "+14155551234":
final phone = _phoneKey.currentState?.value;
Important: defaultCountryCode is required by design — this package does not attempt to auto-detect a user's country from device locale, since a phone's display-language setting is not a reliable proxy for actual location. Set it to whichever country your app primarily targets; users elsewhere can switch via the flag picker at any time.
Section 4: OTP / PIN Input (SmartOtpConfig) #
SmartOtpField Previews
| Basic 6-Digit OTP | Auto-Submit & Autofill |
|---|---|
![]() |
![]() |
1. Basic 6-Digit OTP
SmartFormField(
config: SmartOtpConfig(
label: 'Verification Code',
helperText: 'Sent to your phone via SMS',
isRequired: true,
),
)
2. Auto-Submit on Completion
SmartFormField(
config: SmartOtpConfig(
label: 'Verification Code',
autoSubmit: true,
onSubmitted: (code) => verifyOtp(code),
),
)
3. 4-Digit PIN, Masked
SmartFormField(
config: SmartOtpConfig(
label: 'Enter PIN',
length: 4,
obscureText: true,
obscuringCharacter: '*',
enableSmsAutofill: false, // PINs aren't SMS codes
),
)
4. Zero-Touch Background SMS Interception
If your app already reads incoming SMS itself (e.g. via the Android SMS Retriever API), just feed the code into a controller you provide — no special wiring needed on this package's side:
final _otpController = TextEditingController();
SmartFormField(
config: SmartOtpConfig(
label: 'Verification Code',
controller: _otpController,
autoSubmit: true,
),
)
// Elsewhere, once your app's SMS listener receives the code:
_otpController.text = '482913'; // boxes update, autoSubmit fires automatically
5. Custom Box Colors
SmartFormField(
config: SmartOtpConfig(
label: 'Verification Code',
enabledBorderColor: Colors.grey,
focusedBorderColor: Colors.deepPurple,
errorBorderColor: Colors.redAccent,
),
)
SmartTextConfig Property Reference #
| Property | Type | Description |
|---|---|---|
label |
String? |
Field label header shown above input |
hint |
String? |
Placeholder text inside input |
helperText |
String? |
Supporting text shown below field |
isRequired |
bool |
Adds * asterisk and runs empty validation |
validators |
List<SmartValidator> |
Custom validation functions chain |
minLength |
int? |
Minimum character length constraint |
maxLength |
int? |
Maximum character length constraint (renders counter) |
maxLines |
int? |
Maximum lines for multiline input |
minLines |
int? |
Minimum lines for multiline input |
autoCapitalizeWords |
bool |
Automatically capitalizes first letter of every word |
showClearButton |
bool |
Renders (×) clear button when text is non-empty |
prefixIcon |
Widget? |
Icon displayed at the start of input |
suffixIcon |
Widget? |
Icon displayed at the end of input |
onSuffixIconTap |
VoidCallback? |
Tap handler for suffixIcon |
readOnly |
bool |
Focusable and selectable but prevents editing |
enabled |
bool |
Disables field interactions and dims colors |
controller |
TextEditingController? |
External controller override |
focusNode |
FocusNode? |
External focus node override |
nextFocusNode |
FocusNode? |
Focus node to request on keyboard submit |
debounce |
Duration |
Delay for debounced callbacks (default: 300ms) |
onDebouncedChanged |
ValueChanged<String>? |
Sync callback invoked after debounce delay |
onSearchAsync |
Future<void> Function(query, isCurrent)? |
Async search callback with stale response checker |
showSearchLoadingIndicator |
bool |
Auto-swaps suffix icon to spinner during async search |
SmartPasswordConfig Property Reference #
| Property | Type | Description |
|---|---|---|
label |
String? |
Field label header shown above input |
hint |
String? |
Placeholder text inside input |
helperText |
String? |
Supporting text shown below field |
isRequired |
bool |
Adds * asterisk and runs empty validation |
obscuringCharacter |
String |
Mask symbol used when obscured (default: '•') |
showToggleIcon |
bool |
Renders visibility eye icon toggle (default: true) |
toggleIconBuilder |
Widget Function(bool isObscured)? |
Builder for custom visibility toggle icon |
showStrengthMeter |
bool |
Renders animated 4-segment password strength bar (default: true) |
strengthMeterBuilder |
Widget Function(BuildContext, PasswordStrength)? |
Builder for replacing default strength meter UI |
customStrengthScorer |
PasswordStrength Function(String, int)? |
Custom algorithm function for password strength scoring |
minPasswordLength |
int |
Minimum password length requirement & strength threshold baseline (default: 8) |
requireUppercase |
bool |
Requires at least one uppercase letter [A-Z] |
requireLowercase |
bool |
Requires at least one lowercase letter [a-z] |
requireDigit |
bool |
Requires at least one numeric digit [0-9] |
requireSpecialChar |
bool |
Requires at least one special character [!@#$%^&*...] |
confirmPasswordController |
TextEditingController? |
Controller of original password field for match validation |
confirmMismatchMessage |
String? |
Custom error message when confirm password does not match |
SmartPhoneConfig Property Reference #
| Property | Type | Description |
|---|---|---|
label |
String? |
Field label header shown above input |
hint |
String? |
Placeholder text inside input |
helperText |
String? |
Supporting text shown below field |
isRequired |
bool |
Adds * asterisk and runs empty validation |
defaultCountryCode |
String |
Required. ISO 3166-1 alpha-2 starting country (e.g. 'IN', 'US', 'GB') |
onCountryChanged |
void Function(String isoCode, String dialCode)? |
Fires when the user picks a different country |
invalidNumberMessage |
String? |
Custom error message for format validation failure |
showDropdownIcon |
bool |
Show/hide the chevron next to the flag (flag stays tappable either way) |
flagsButtonPadding |
EdgeInsetsGeometry? |
Padding around the flag/dial-code button |
flagsButtonMargin |
EdgeInsets? |
Margin around the flag/dial-code button |
validateMode |
AutovalidateMode |
Controls live re-validation behavior as the user types |
controller |
TextEditingController? |
External controller override (holds the national number) |
focusNode / nextFocusNode |
FocusNode? |
External focus control / focus traversal target |
validators |
List<SmartValidator> |
Custom validators — receive the raw national number, no dial code |
SmartOtpConfig Property Reference #
| Property | Type | Description |
|---|---|---|
label |
String? |
Field label header shown above the boxes |
helperText |
String? |
Supporting text shown below the boxes |
isRequired |
bool |
Adds * asterisk and runs empty validation |
length |
int |
Number of boxes / required code length (default: 6) |
obscureText |
bool |
Mask entered digits like a PIN |
obscuringCharacter |
String |
Mask symbol used when obscureText is true (default: '●') |
enableSmsAutofill |
bool |
Enable native SMS/platform autofill via AutofillHints.oneTimeCode |
onCompleted |
ValueChanged<String>? |
Fires once each time the code reaches full length |
autoSubmit |
bool |
Auto-dismiss keyboard and fire onSubmitted on completion |
enabledBorderColor |
Color? |
Box border color in normal state (field-level override) |
focusedBorderColor |
Color? |
Box border color for the currently active box |
errorBorderColor |
Color? |
Box border color when validation fails |
controller |
TextEditingController? |
External controller — supports zero-touch SMS interception by assignment |
validators |
List<SmartValidator> |
Custom validators — receive the full entered code as one string |
🤝 Community, Feedback & Contributing #
Why use smart_multi_form_fields? #
Form building in Flutter shouldn't require copy-pasting hundreds of lines of TextFormField boilerplate or mixing separate third-party packages for every input type.
smart_multi_form_fields unifies all your form fields into a single, production-grade widget with compile-time type safety, theme adaptability, built-in validation rules, animated strength feedback, and zero maintenance bloat.
If this package saves you development time or makes your Flutter codebase cleaner, please ⭐ star the repository on GitHub to support the project!
🐛 How to Report Issues & Request Features #
We welcome feature requests, bug reports, and pull requests! To ensure issues are resolved as quickly as possible, please follow these guidelines when opening a GitHub issue.
Steps to File an Issue:
- Check existing GitHub Issues to verify your bug or feature request hasn't already been reported.
- Click New Issue on the repository's Issues tab.
- Provide the required details listed below.
Required Issue Details Checklist:
- 📌 Environment Info: Include output of
flutter doctor -v(Flutter SDK and Dart versions). - 📦 Package Version: State the package version used (e.g.
smart_multi_form_fields: ^1.1.0). - 🧩 Config Type: Specify which configuration was used (e.g.
SmartTextConfigorSmartPasswordConfig). - 📝 Minimal Reproducible Code: Provide a complete, self-contained Flutter snippet reproducing the behavior.
- 🎯 Expected vs Actual Behavior: Clearly describe what should happen vs what actually occurred.
- 📷 Screenshots / Logs: Attach error stack traces or visual screenshots if applicable.
License #
MIT License.







