VooForms

A comprehensive, type-safe forms package for Flutter with clean architecture, atomic design pattern, and excellent developer experience.

pub package License: MIT

โœจ Features

  • ๐ŸŽฏ Type-Safe Fields - Full type safety with generics throughout
  • ๐Ÿ›๏ธ Clean Architecture - Follows SOLID principles with clear separation of concerns
  • ๐ŸŽจ Atomic Design - Components organized as atoms, molecules, and organisms
  • ๐Ÿ“ฑ Cross-Platform - Works seamlessly on iOS, Android, Web, Desktop
  • ๐ŸŽจ Material 3 - Built with the latest Material Design guidelines
  • โœ… Rich Validators - 13+ built-in validators with composable validation
  • ๐Ÿ”ง Smart Formatters - 12+ formatters for phone, credit card, currency, etc.
  • ๐ŸŽฎ Powerful Controller - Advanced form state management
  • ๐Ÿ“ Multiple Layouts - Vertical, grid, stepped, tabbed layouts
  • ๐Ÿš€ Excellent DX - Intuitive API with great IDE support

๐Ÿ“ฆ Installation

Add voo_forms to your pubspec.yaml:

dependencies:
  voo_forms: ^0.3.2

๐Ÿš€ Quick Start

Simple Form Example

import 'package:voo_forms/voo_forms.dart';

// Create a form using direct widget instantiation
final form = VooForm(
  fields: [
    VooTextField(
      name: 'username',
      label: 'Username',
      validators: [
        RequiredValidation(),
        MinLengthValidation(minLength: 3),
      ],
    ),
    VooEmailField(
      name: 'email',
      label: 'Email Address',
      validators: [
        RequiredValidation(),
        EmailValidation(),
      ],
    ),
    VooPasswordField(
      name: 'password',
      label: 'Password',
      validators: [
        RequiredValidation(),
        MinLengthValidation(minLength: 8),
        PatternValidation(
          pattern: r'^(?=.*[A-Z])(?=.*[0-9])',
          errorMessage: 'Must contain uppercase and number',
        ),
      ],
    ),
  ],
);

Organizing Fields with Sections

// Group related fields in collapsible sections
final form = VooForm(
  fields: [
    VooFormSection(
      title: 'Personal Information',
      description: 'Enter your basic details',
      isCollapsible: true,
      children: [
        VooTextField(name: 'firstName', placeholder: 'First Name'),
        VooTextField(name: 'lastName', placeholder: 'Last Name'),
        VooDateField(name: 'birthDate', label: 'Date of Birth'),
      ],
    ),
    VooFormSection(
      title: 'Contact Details',
      children: [
        VooEmailField(name: 'email', label: 'Email'),
        VooPhoneField(name: 'phone', label: 'Phone'),
      ],
    ),
  ],
);

๐ŸŽจ Field Types

VooForms provides direct widget classes for all field types:

// Text Fields
VooTextField(name: 'username', label: 'Username')
VooEmailField(name: 'email', label: 'Email')
VooPasswordField(name: 'password', label: 'Password')
VooPhoneField(name: 'phone', label: 'Phone')
VooMultilineField(name: 'bio', label: 'Bio')
VooNumberField(name: 'age', label: 'Age')

// Selection Fields
VooDropdownField<String>(
  name: 'country',
  label: 'Country',
  options: ['United States', 'United Kingdom', 'Canada'],
)
VooCheckboxField(name: 'terms', label: 'Accept Terms')
VooBooleanField(name: 'newsletter', label: 'Subscribe')

// Date & Time
VooDateField(name: 'birthday', label: 'Birthday')
VooDateFieldButton(name: 'appointment', label: 'Appointment Date')

// Numeric Fields
VooIntegerField(name: 'age', label: 'Age')
VooDecimalField(name: 'price', label: 'Price')
VooCurrencyField(name: 'salary', label: 'Salary')
VooPercentageField(name: 'discount', label: 'Discount')

// Other Types
VooFileField(name: 'avatar', label: 'Avatar')
VooListField<String>(
  name: 'tags',
  label: 'Tags',
  items: tags,
  itemBuilder: (tag) => Chip(label: Text(tag)),
)

โœ… Validators

Built-in Validators

Each validator is in its own file for better organization:

// Basic Validators
RequiredValidation()
EmailValidation()
PhoneValidation()
UrlValidation()

// String Validators
MinLengthValidation(minLength: 3)
MaxLengthValidation(maxLength: 50)
PatternValidation(pattern: r'^[A-Z]', errorMessage: 'Must start with capital')

// Numeric Validators
MinValueValidation(minValue: 0)
MaxValueValidation(maxValue: 100)
RangeValidation(minValue: 0, maxValue: 100)

// Date Validators
DateRangeValidation(
  minDate: DateTime(2020),
  maxDate: DateTime(2030),
)

// Custom Validation
CustomValidation(
  validator: (value) {
    if (value == 'admin') return 'Username not available';
    return null;
  },
)

// Combine Multiple Validators
CompoundValidation(rules: [
  RequiredValidation(),
  EmailValidation(),
])

Creating Custom Validators

class PasswordMatchValidation extends VooValidationRule<String> {
  final String Function() getPassword;
  
  PasswordMatchValidation({required this.getPassword})
    : super(errorMessage: 'Passwords do not match');
  
  @override
  String? validate(String? value) {
    if (value != getPassword()) {
      return errorMessage;
    }
    return null;
  }
}

๐Ÿ”ง Formatters

Smart input formatting for better UX:

// Phone Formatters
VooFormatters.phoneUS()              // (123) 456-7890
VooFormatters.phoneInternational()   // +1 234 567 8900

// Card & Financial
VooFormatters.creditCard()           // 1234 5678 9012 3456
VooFormatters.currency(symbol: '\$') // $1,234.56

// Date Formatters
VooFormatters.dateUS()               // MM/DD/YYYY
VooFormatters.dateEU()               // DD/MM/YYYY
VooFormatters.dateISO()              // YYYY-MM-DD

// Text Formatters
VooFormatters.uppercase()
VooFormatters.lowercase()
VooFormatters.alphanumeric()
VooFormatters.numbersOnly()

// US Specific
VooFormatters.ssn()                  // 123-45-6789
VooFormatters.zipCode()              // 12345 or 12345-6789

// Custom Patterns
VooFormatters.mask('###-##-####')    // Custom mask
VooFormatters.pattern(
  pattern: 'AA-####',
  patternMapping: {
    'A': RegExp(r'[A-Z]'),
    '#': RegExp(r'[0-9]'),
  },
)

๐ŸŽญ Field Options

Customize field appearance and behavior:

VooField.text(
  name: 'username',
  options: VooFieldOptions(
    // Label positioning
    labelPosition: LabelPosition.floating,  // or above, left, placeholder, hidden
    
    // Field styling
    fieldVariant: FieldVariant.filled,     // or outlined, underlined, ghost, rounded, sharp
    
    // Validation behavior
    validateOnChange: true,
    validateOnFocusLost: true,
    
    // Error display
    errorDisplayMode: ErrorDisplayMode.always,  // or onFocus, onSubmit
    
    // Focus behavior
    focusBehavior: FocusBehavior.next,     // or submit, none
  ),
)

Preset Options

Use built-in presets for consistency:

options: VooFieldOptions.material     // Material Design defaults
options: VooFieldOptions.comfortable  // Spacious layout
options: VooFieldOptions.compact      // Dense layout
options: VooFieldOptions.minimal      // Minimal styling

๐ŸŽฎ Form Controller

Advanced form control:

final controller = VooFormController(
  form: form,
  onFieldChange: (field, value) {
    print('${field.name} changed to $value');
  },
  onValidationChange: (isValid) {
    print('Form valid: $isValid');
  },
);

// Programmatic control
controller.setValue('username', 'john_doe');
controller.getValue('username');  // 'john_doe'
controller.validate();            // Validate all fields
controller.validateField('email'); // Validate specific field
controller.reset();               // Reset to initial values
controller.clear();               // Clear all values
controller.submit();              // Submit the form

// Field management
controller.enableField('email');
controller.disableField('password');
controller.showField('optional');
controller.hideField('advanced');
controller.focusField('username');

๐Ÿ“ Layouts

Multiple layout options:

Vertical Layout (Default)

VooFormVerticalLayout(
  fields: fields,
  spacing: 16.0,
)

Grid Layout

VooFormGridLayout(
  fields: fields,
  columns: 2,
  spacing: 16.0,
  crossAxisSpacing: 12.0,
)

Stepped Layout (Wizard)

VooFormSteppedLayout(
  steps: [
    VooFormStep(
      title: 'Personal Info',
      fields: [/* fields */],
    ),
    VooFormStep(
      title: 'Contact',
      fields: [/* fields */],
    ),
  ],
)

Tabbed Layout

VooFormTabbedLayout(
  tabs: [
    VooFormTab(
      label: 'Basic',
      fields: [/* fields */],
    ),
    VooFormTab(
      label: 'Advanced',
      fields: [/* fields */],
    ),
  ],
)

Support for dynamic dropdown options:

// Async dropdown with search
VooField.dropdown<City>(
  name: 'city',
  label: 'City',
  enableSearch: true,
  asyncOptionsLoader: (query) async {
    final cities = await api.searchCities(query);
    return cities.map((city) => VooFieldOption(
      value: city,
      label: city.name,
      subtitle: city.state,
      icon: Icons.location_city,
    )).toList();
  },
)

๐Ÿงช Testing

VooForms is designed for easy testing:

testWidgets('Form submission', (tester) async {
  final form = VooForm(
    fields: [
      VooField.text(name: 'username'),
      VooField.email(name: 'email'),
    ],
    onSubmit: expectAsync1((values) {
      expect(values['username'], 'testuser');
      expect(values['email'], 'test@example.com');
    }),
  );
  
  await tester.pumpWidget(MaterialApp(home: form));
  
  // Enter values
  await tester.enterText(
    find.byType(TextFormField).first,
    'testuser',
  );
  await tester.enterText(
    find.byType(TextFormField).last,
    'test@example.com',
  );
  
  // Submit
  await tester.tap(find.text('Submit'));
  await tester.pump();
});

๐Ÿ›๏ธ Architecture

VooForms follows clean architecture principles:

Presentation Layer (UI/Widgets)
        โ†“
Domain Layer (Entities/Business Logic)  
        โ†“
Data Layer (Models/Repositories)

Atomic Design Pattern

  • Atoms: Basic input widgets (text field, checkbox, etc.)
  • Molecules: Composed components (field with label, field with error)
  • Organisms: Complete forms and layouts

Key Principles

  • One class per file - Better organization and navigation
  • No _buildXXX methods - Using helper classes instead
  • Clean imports - No relative imports, properly ordered
  • Type safety - Generics used throughout
  • SOLID principles - Single responsibility, open/closed, etc.

๐ŸŽจ Theming

VooForms respects your app's Material theme:

MaterialApp(
  theme: ThemeData(
    colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
    useMaterial3: true,
  ),
  home: MyApp(),
)

๐Ÿ“– Documentation

๐Ÿค Contributing

Contributions welcome! Please ensure:

  • Follow clean architecture principles
  • One class per file
  • No _buildXXX methods returning widgets
  • Add tests for new features
  • Update documentation

๐Ÿ“„ License

MIT License - see LICENSE file for details.


Built by VooStack

Need help with Flutter development or custom form solutions?

Contact Us

VooStack builds enterprise Flutter applications and developer tools. We're here to help with your next project.


๐Ÿš€ What's New in 0.1.14

  • Major Technical Debt Cleanup - Eliminated all _buildXXX methods
  • Better Organization - 25+ classes split into individual files
  • Improved DX - Each validator/formatter in its own file
  • Clean Architecture - Proper separation of concerns throughout
  • Enhanced Testing - 92.6% test success rate

See CHANGELOG.md for full details.

Libraries

voo_forms