form_field_adapter 1.0.2 copy "form_field_adapter: ^1.0.2" to clipboard
form_field_adapter: ^1.0.2 copied to clipboard

An interactive, focus-aware FormField wrapper that adds delightful state-based decorations, shake animations, and haptic feedback to any custom widget.

FormFieldAdapter #

pub version likes license

FormFieldAdapter Demo Mobile

An interactive, focus-aware FormField wrapper designed for Flutter.

FormFieldAdapter simplifies turning any custom input widget (such as rating selectors, multi-select tag chips, map pin pickers, or image uploads) into a fully integrated form field with validation, animated visual feedback, and zero boilerplate.


Features #

  • State-Based Animated Decorations: Smoothly morphs between four custom Decoration states ( Normal, Focused, Error, and Focused Error).
  • Shake Animation: Naturally shakes the input container horizontally when validation fails to instantly capture user attention. Skipped automatically when the system's reduce-motion setting is on.
  • Haptic Feedback: Triggers a subtle, light device vibration whenever an error is first caught.
  • Focus Node Integration: Listens to a standard Flutter FocusNode to trigger active/idle styling changes. You attach the same node to a Focus widget inside builder (see below).
  • Accessible Errors: Error text is announced to screen readers as a live region.
  • Flexible Error Placement: Choose whether standard error messages should appear above the field, below the field, or be hidden entirely (to display custom alert layouts instead).
  • Flexible Layout Alignment: Align the entire wrapper and its error text to the start, center, or end to support centered widgets like profile avatars and rating bars.
  • Automatic Theme Integration: Falls back to your app's ThemeData (error and primary colors, and inputDecorationTheme.errorStyle for the error text) if custom values aren't passed.
  • Works with a plain Form: No extra form wrapper or dependencies. RTL layouts are supported.
  • Universal Compatibility: Works on mobile, tablet, desktop, and web.

Installation #

Add form_field_adapter to your pubspec.yaml dependencies:

dependencies:
  form_field_adapter: ^1.0.2

And run:

flutter pub get

Quick Start #

Wrap any interactive widget inside the FormFieldAdapter to connect it with your parent Form:

import 'package:flutter/material.dart';
import 'package:form_field_adapter/form_field_adapter.dart';

class RatingForm extends StatefulWidget {
  const RatingForm({super.key});

  @override
  State<RatingForm> createState() => _RatingFormState();
}

class _RatingFormState extends State<RatingForm> {
  final _formKey = GlobalKey<FormState>();
  final _focusNode = FocusNode();
  int _userRating = 0;

  @override
  void dispose() {
    _focusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          FormFieldAdapter<int>(
            initialValue: _userRating,
            focusNode: _focusNode,
            validator: (value) =>
                (value == null || value < 3) ? 'Must rate at least 3 stars!' : null,
            onSaved: (value) => _userRating = value ?? 0,
            builder: (state) {
              // Attach the same focus node here, or the focused styles never apply.
              return Focus(
                focusNode: _focusNode,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: List.generate(5, (index) {
                    return IconButton(
                      icon: Icon(
                        index < (state.value ?? 0) ? Icons.star : Icons.star_border,
                        color: Colors.amber,
                      ),
                      onPressed: () {
                        state.didChange(index + 1);
                        _focusNode.requestFocus();
                      },
                    );
                  }),
                ),
              );
            },
          ),
          ElevatedButton(
            onPressed: () {
              if (_formKey.currentState!.validate()) {
                _formKey.currentState!.save();
                debugPrint('Validation passed! Rating is $_userRating');
              }
            },
            child: const Text('Submit'),
          ),
        ],
      ),
    );
  }
}

Advanced Customization #

For full-control designs, wrap your custom widgets inside a builder method to satisfy your design requirements:

import 'package:flutter/material.dart';
import 'package:form_field_adapter/form_field_adapter.dart';

Widget buildCustomAdapter(FocusNode myFocusNode) {
  return FormFieldAdapter<String?>(
    focusNode: myFocusNode,
    errorPosition: ErrorPosition.top,
    // Places the error text above the input
    enableHaptics: true,
    // Enable device vibrations
    enableShake: true,
    // Enable failure shake animation

    // Design completely custom border styles
    normalDecoration: BoxDecoration(
      borderRadius: BorderRadius.circular(8),
      border: Border.all(color: Colors.grey.shade300),
    ),
    focusedDecoration: BoxDecoration(
      borderRadius: BorderRadius.circular(8),
      border: Border.all(color: Colors.deepPurple, width: 2),
    ),
    errorDecoration: BoxDecoration(
      borderRadius: BorderRadius.circular(8),
      border: Border.all(color: Colors.red, width: 1.5),
    ),
    builder: (state) {
      return const SizedBox.shrink(); // Replace with your custom widget
    },
  );
}

Properties #

Property Type Default Description
builder Widget Function(FormFieldState<T>) Required Renders your custom input widget.
initialValue T? null Initial value of the field. Restored by FormState.reset().
validator String? Function(T?)? null Returns an error message, or null when the value is valid.
onSaved void Function(T?)? null Called by FormState.save().
autoValidateMode AutovalidateMode? AutovalidateMode.onUserInteraction Spelled differently from Flutter's autovalidateMode; the framework default is disabled.
enabled bool true Forwarded to FormField: when false, automatic validation is off, but FormState.validate() still validates it. No separate styling.
focusNode FocusNode? null Listened to for focus changes. Attach the same node to a Focus widget in builder.
normalDecoration Decoration? null Style applied when the field is valid and not focused.
focusedDecoration Decoration? null Style applied when the field is valid and focused. Falls back to normalDecoration.
errorDecoration Decoration? null Style applied when the field has a validation error and is not focused.
focusedErrorDecoration Decoration? null Style applied when the field has an error and is focused. Falls back to errorDecoration.
decorationPlacement DecorationPlacement DecorationPlacement.background Renders decoration behind (background) or as a stack overlay (foreground).
enableShake bool true Triggers a horizontal shake on validation error. Skipped when reduce-motion is on.
enableHaptics bool true Triggers light haptic feedback on devices on validation error.
animationDuration Duration 200ms Transition duration between the decoration states.
crossAxisAlignment CrossAxisAlignment CrossAxisAlignment.start Aligns the outer layout container (start, center, or end).
errorTextAlign TextAlign? null Custom error text alignment. Automatically matches crossAxisAlignment if left null.
errorPosition ErrorPosition ErrorPosition.bottom Location of the error message (top, bottom, or none).
errorTextStyle TextStyle? null Typography for the validation error message.
errorPadding EdgeInsetsGeometry? null Custom margins around the error message. Default: 6 px above/below and 4 px at the start.
errorBuilder Widget Function(BuildContext, String)? null Completely custom render callback for the error layout.

Tip: keep the border widths of your custom decorations equal across states. A Border adds to the field's size, so different widths make the layout jump when focus or error state changes.


Platforms Supported #

  • iOS
  • Android
  • Web
  • macOS
  • Windows
  • Linux

Contributions Welcome #

Found a bug or want to improve this widget? Open an issue or pull request on GitHub: github.com/hbsgujjar111/form_field_adapter


License #

This project is licensed under the MIT License - see the LICENSE file for details.

1
likes
160
points
28
downloads
screenshot

Documentation

API reference

Publisher

verified publishermobiledevhassan.pk

Weekly Downloads

An interactive, focus-aware FormField wrapper that adds delightful state-based decorations, shake animations, and haptic feedback to any custom widget.

Repository (GitHub)
View/report issues

Topics

#form #validation #animation #widget #haptics

License

MIT (license)

Dependencies

flutter

More

Packages that depend on form_field_adapter