formix 0.0.4 copy "formix: ^0.0.4" to clipboard
formix: ^0.0.4 copied to clipboard

An elite, type-safe, and ultra-reactive form engine for Flutter powered by Riverpod.

Formix 🚀 #

Formix Logo

Pub License Code Coverage Tests

An elite, type-safe, and ultra-reactive form engine for Flutter.

Powered by Riverpod, Formix delivers lightning-fast performance, zero boilerplate, and effortless state management. Whether it's a simple login screen or a complex multi-step wizard, Formix scales with you.


📑 Table of Contents #


📦 Installation #

flutter pub add formix

⚡ Quick Start #

1. Define Fields #

final emailField = FormixFieldID<String>('email');
final ageField = FormixFieldID<int>('age');

2. Build Form #

Formix(
  child: Column(
    children: [
      RiverpodTextFormField(fieldId: emailField),
      RiverpodNumberFormField(fieldId: ageField),

      FormixBuilder(
        builder: (context, scope) => ElevatedButton(
          onPressed: scope.watchIsValid ? () => scope.submit() : null,
          child: Text('Submit'),
        ),
      ),
    ],
  ),
)

🎮 Choosing Your API (Comparison) #

API Best For Rebuilds UI? DX Rank
FormixBuilder Granular UI updates (Buttons, status labels) ✅ Yes ⭐️⭐️⭐️⭐️⭐️
FormixListener Side effects (Logic, Nav, Snackbar) ❌ No ⭐️⭐️⭐️⭐️⭐️
GlobalKey External Control (AppBar, FAB, Logic) ❌ No ⭐️⭐️⭐️⭐️
ref.watch(fieldValueProvider) Cross-field logic within Consumer ✅ Yes ⭐️⭐️⭐️⭐️

🎨 UI Components #

Available Fields #

Formix comes with pre-built, high-performance widgets that work instantly:

  • RiverpodTextFormField: Full-featured text input with auto-validation and dirty state indicators.
  • RiverpodNumberFormField: Type-safe numeric input with support for min/max constraints.
  • RiverpodCheckboxFormField: Reactive checkbox with built-in label support.
  • RiverpodDropdownFormField<T>: Type-safe generic dropdown for selections.
  • RiverpodFormStatus: A debug/status card that shows current form validity, dirty state, and submission progress.

Custom Field Widgets #

Need a custom UI? Extend FormixFieldWidget to create a fully integrated form field in seconds.

class MyCustomToggle extends FormixFieldWidget<bool> {
  const MyCustomToggle({super.key, required super.fieldId});

  @override
  Widget build(BuildContext context) {
    // Access value, validation, and dirty state directly!
    return Switch(
      value: value ?? false,
      onChanged: (v) => didChange(v), // Notifies the form
    );
  }
}

🚥 Validation & UX #

Formix provides a multi-layered validation system designed for an elite user experience.

Sync & Async Validation #

Define rules in FormixFieldConfig. Sync rules run immediately on every keystroke, while Async rules are intelligently debounced.

FormixFieldConfig<String>(
  id: usernameField,
  // 🟢 Sync: Immediate feedback
  validator: (val) => val!.length < 3 ? 'Too short' : null,

  // 🔵 Async: Intelligent Debouncing (Default 300ms)
  asyncValidator: (val) async {
    final available = await checkUsername(val!);
    return available ? null : 'Username taken';
  },
  debounceDuration: const Duration(milliseconds: 500),
)

UX Tip: Formix widgets automatically show a CircularProgressIndicator while async rules are running! You can customize this by passing loadingIcon (or validatingWidget for checkboxes) to your field widget.

Fluent Validation API #

Define complex rules easily with the Zod-like FormixValidators API:

FormixFieldConfig<String>(
  id: emailField,
  validator: FormixValidators.string()
    .required()
    .email('Please enter a valid email')
    .minLength(5)
    .build(), // Returns a standard validator function
)

Manual/Backend Errors #

Sometimes errors come from the server after a submit attempt. Use setFieldError to inject these errors directly into your UI.

final controller = Formix.controllerOf(context);

try {
  await api.submit(data);
} catch (e) {
  if (e is ValidationError) {
    // Map backend errors to specific fields!
    controller?.setFieldError(emailField, 'Email already exists on server');
  }
}

🌍 Localization (i18n) #

Formix speaks your language! It comes with built-in translations for English, Spanish, French, German, Hindi, and Chinese.

1. Automatic Usage (Zero Config) #

Just use FormixLocalizations.of(context) in your validators. It automatically detects the active locale from MaterialApp.

validator: (value, context) {
  final messages = FormixLocalizations.of(context);
  if (value == null || value.isEmpty) {
    return messages.required('Email'); // Returns "Email is required" (or localized equivalent)
  }
  return null;
}

2. Using the Delegate (Optional) #

For the best integration with Flutter's widget tree (and to strictly follow Flutter standards), you can add the delegate to your MaterialApp. This is completely optional—the method above works without it!

MaterialApp(
  localizationsDelegates: const [
    FormixLocalizations.delegate, // Optional: Add this
    GlobalMaterialLocalizations.delegate,
    // ...
  ],
  // ...
)

🏗️ The Three Pillars of Formix #

1. Inside the Tree (Reactive UI) #

Use FormixBuilder for code that lives inside the form and needs to react to state changes.

FormixBuilder(
  builder: (context, scope) => Text('Age: ${scope.watchValue(ageField)}'),
)

2. Outside the Tree (External Control) #

Access the form from your Scaffold's AppBar using a GlobalKey.

final _formKey = GlobalKey<FormixState>();
// ...
onPressed: () => _formKey.currentState?.controller.submit(...)

3. Listening to Changes (Side Effects) #

Use FormixListener for navigation or snackbars. It doesn't trigger rebuilds.

FormixListener(
  formKey: _formKey,
  listener: (context, state) => print('Valid: ${state.isValid}'),
  child: Formix(key: _formKey, ...),
)

🚀 Advanced Patterns #

Dynamic Form Arrays #

Manage lists of dynamic inputs easily with FormixArray.

FormixArray<String>(
  id: hobbiesId,
  itemBuilder: (context, index, itemId, scope) =>
    RiverpodTextFormField(fieldId: itemId),
)

Computed & Derived Fields #

Update fields automatically based on other values.

FormixFieldDerivation(
  dependencies: [priceField, quantityField],
  targetField: totalField,
  derive: (v) => (v[priceField] ?? 0.0) * (v[quantityField] ?? 1),
)

📊 Analytics & Debugging #

Understand exactly how your users interact with your forms.

Logging Analytics (Built-in) #

See every field change, validation event, and submission in your debug console:

Formix(
  analytics: const LoggingFormAnalytics(), // Auto-logs to console in debug mode
  child: Column(
    children: [
      // ... fields
    ],
  ),
)

💡 Pro Tips #

  • 💡 keepAlive: Maintain state in TabViews/Steppers.
  • 💡 Formix.of(context): Quick access to the controller provider.
  • 💡 FormixNavigationGuard: Block accidental "Back" button presses when the form is dirty.

🧬 Advanced Logic #

Multi-Step Forms (Steppers) #

Validate only the current step's fields before moving forward.

onStepContinue: () {
  // Only validate fields relevant to Step 1
  if (controller.validate(fields: [firstName, lastName])) {
    setState(() => _step++);
  }
}

Multi-Form Synchronization #

Link fields between completely separate forms (e.g., a "Profile" form and a "Checkout" form).

// In your business logic or init
checkoutController.bindField(
  billingAddress,
  sourceController: profileController,
  sourceField: profileAddress,
  twoWay: true, // Optional: Sync both ways
);

Optimistic Updates #

Perform immediate UI updates while waiting for async operations (like server saves). If the operation fails, the value automatically reverts.

await controller.optimisticUpdate(
  fieldId: usernameField,
  value: 'new_username',
  action: () async {
    await api.updateUsername('new_username');
  },
  revertOnError: true, // Default
);

Undo/Redo History #

Built-in state history allows you to implement undo/redo functionality effortlessly.

if (controller.canUndo) controller.undo();
if (controller.canRedo) controller.redo();

Automatic Focus Management #

Formix automatically handles focus traversal:

  • Enter-to-Next: Pressing "Enter" on the keyboard focuses the next field.
  • Submit-to-Error: On submission failure, the first invalid field is focused and scrolled into view.
// Enabled by default!
// Customize via textInputAction in FormixFieldConfig
FormixFieldConfig<String>(
  id: emailField,
  textInputAction: TextInputAction.next, // Default
)

Built with ❤️ for the Flutter Community

4
likes
0
points
561
downloads

Publisher

verified publishershreeman.dev

Weekly Downloads

An elite, type-safe, and ultra-reactive form engine for Flutter powered by Riverpod.

Homepage
Repository (GitHub)
View/report issues

Topics

#form #validation #riverpod #type-safe #state-management

License

unknown (license)

Dependencies

collection, flutter, flutter_riverpod, index_generator, meta

More

Packages that depend on formix