Skip to main content

flutterx_forms 2.0.1 copy "flutterx_forms: ^2.0.1" to clipboard
flutterx_forms: ^2.0.1 copied to clipboard

Declarative Flutter forms with typed fields, validators, number, date, file and list inputs, a form controller and drop support.

example/lib/main.dart

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

void main() => runApp(const ExampleApp());

/// Shows a form with a text, a number, a date, a file and a list field, and the values it submits.
class ExampleApp extends StatelessWidget {
  /// Creates the example app.
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) => MaterialApp(
    theme: ThemeData(primarySwatch: Colors.green).copyWith(
      outlinedButtonTheme: OutlinedButtonThemeData(
        style: OutlinedButton.styleFrom(
          iconSize: 20,
          shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))),
        ),
      ),
      inputDecorationTheme: InputDecorationTheme(
        border: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(8))),
        focusedBorder: OutlineInputBorder(
          borderRadius: const BorderRadius.all(Radius.circular(12)),
          borderSide: BorderSide(color: Colors.deepPurple.shade400, width: 3),
        ),
      ),
    ),
    home: const Scaffold(
      body: SafeArea(child: SingleChildScrollView(child: ExampleForm())),
    ),
  );
}

/// The form of the example: its fields are created and disposed by the [FormController] mixin.
class ExampleForm extends StatefulWidget {
  /// Creates the form.
  const ExampleForm({super.key});

  @override
  State<ExampleForm> createState() => _ExampleFormState();
}

class _ExampleFormState extends State<ExampleForm> with FormController<ExampleForm> {
  late final XFormField<String> _name = field();
  late final XFormField<int?> _age = field();
  late final XFormField<DateTime?> _birthday = field();
  late final XFormField<XFile?> _photo = field();
  late final XFormField<List<String>> _tags = field();
  String _submitted = '';

  @override
  Widget build(BuildContext context) => Padding(
    padding: const EdgeInsets.all(16),
    child: buildForm(
      autovalidateMode: AutovalidateMode.onUserInteraction,
      children: [
        XTextFormField(
          field: _name,
          decoration: const InputDecoration(labelText: 'Name'),
          textInputAction: TextInputAction.next,
          validator: validateFirst([
            nonBlank(() => 'The name is required'),
            minLen(2, () => 'At least 2 characters'),
            maxLen(20, () => 'At most 20 characters'),
          ]),
        ),
        const SizedBox(height: 16),
        XIntFormField(
          field: _age,
          decoration: const InputDecoration(labelText: 'Age'),
          max: 120,
          validator: gte<int>(18, () => 'You must be 18 or older'),
        ),
        const SizedBox(height: 16),
        XDateTimeFormField(
          field: _birthday,
          decoration: const InputDecoration(labelText: 'Birthday'),
          lastDate: DateTime(2100),
        ),
        const SizedBox(height: 16),
        XFileFormField(
          field: _photo,
          decoration: const InputDecoration(labelText: 'Photo'),
          mimeTypes: const {'image/*'},
        ),
        const SizedBox(height: 16),
        XListFormField<String>(
          field: _tags,
          decoration: const InputDecoration(labelText: 'Tags'),
          maxLength: 3,
          addButtonText: 'Add tag',
          itemInitialValue: (values, index) => '',
          validator: validateFirst([listNonEmpty<String>(() => 'Add at least one tag').cast()]),
          itemBuilder: (state, field, values, index) => XTextFormField(
            field: field,
            initialValue: values[index],
            decoration: InputDecoration(labelText: 'Tag ${index + 1}'),
            validator: nonBlank(() => 'The tag is required'),
          ),
        ),
        const SizedBox(height: 16),
        Row(
          children: [
            FilledButton(onPressed: submitForm, child: const Text('Submit')),
            const SizedBox(width: 8),
            OutlinedButton(onPressed: resetForm, child: const Text('Reset')),
          ],
        ),
        if (_submitted.isNotEmpty) Padding(padding: const EdgeInsets.only(top: 16), child: Text(_submitted)),
      ],
    ),
  );

  @override
  void onFormSubmit() => setState(
    () => _submitted =
        '${_name.value}, ${_age.value}, ${_birthday.value}, ${_photo.value?.name}, ${_tags.value.join('/')}',
  );
}
2
likes
145
points
343
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Declarative Flutter forms with typed fields, validators, number, date, file and list inputs, a form controller and drop support.

Homepage

License

BSD-3-Clause (license)

Dependencies

clock, collection, cross_file, file_selector, flutter, flutterx_utils, intl, mime, web

More

Packages that depend on flutterx_forms