Form

Date Field

A date field allows a date to be selected from a calendar or input field.

It is recommended to use FDateField.calendar on touch devices and FDateField.new/FDateField.input on non-primarily touch devices.

The input field supports both arrow key navigation:

  • Up/Down arrows: Increment/decrement values
  • Left/Right arrows: Move between date segments

The input field does not support the following locales that use non-western numerals, it will default to English:

  • Arabic
  • Assamese
  • Bengali
  • Persian/Farsi
  • Marathi
  • Burmese
  • Nepali
  • Pashto
  • Tamil
FDateField(
  label: const Text('Appointment Date'),
  description: const Text('Select a date for your appointment'),
);

CLI

To generate and customize this style:

dart run forui style create date-field

Usage

FDateField(...)

FDateField(
  control: FDateFieldControl.managed(
    initial: DateTime(2024, 1, 1),
    validator: (date) => date?.isBefore(DateTime.now()) ?? false ? 'Date must be in the future' : null,
  ),
  style: (style) => style.copyWith(...),
  label: const Text('Select Date'),
  description: const Text('Choose a date from the calendar or input field'),
  textAlign: TextAlign.start,
  textAlignVertical: TextAlignVertical.center,
  autofocus: false,
  expands: false,
  onEditingComplete: () {},
  onSubmit: (date) {},
  mouseCursor: SystemMouseCursors.text,
  canRequestFocus: true,
  baselineInputYear: 2000,
  builder: (context, style, states, child) => child!,
  prefixBuilder: (context, style, states) => const Icon(FIcons.calendar),
  suffixBuilder: (context, style, states) => const Icon(FIcons.calendar),
  clearable: true,
  calendar: FDateFieldCalendarProperties(),
  enabled: true,
  onSaved: (date) {},
  onReset: () {},
  autovalidateMode: AutovalidateMode.onUnfocus,
  forceErrorText: null,
  errorBuilder: (context, error) => Text(error),
);

FDateField.calendar(...)

FDateField.calendar(
  control: FDateFieldControl.managed(initial: DateTime(2024, 1, 1)),
  style: (style) => style.copyWith(...),
  label: const Text('Calendar Date'),
  description: const Text('Select a date from the calendar'),
  format: DateFormat('d MMM y'),
  hint: 'Select a date',
  textAlign: TextAlign.start,
  textAlignVertical: TextAlignVertical.center,
  expands: false,
  mouseCursor: SystemMouseCursors.text,
  canRequestFocus: true,
  clearable: true,
  start: DateTime(2024),
  end: DateTime(2025),
  today: DateTime.now(),
  initialType: FCalendarPickerType.yearMonth,
  autoHide: true,
  anchor: Alignment.topLeft,
  fieldAnchor: Alignment.bottomLeft,
  spacing: FPortalSpacing(4),
  overflow: FPortalOverflow.flip,
  offset: Offset.zero,
  hideRegion: FPopoverHideRegion.excludeChild,
  builder: (context, style, states, child) => child!,
  prefixBuilder: (context, style, states) => const Icon(FIcons.calendar),
  suffixBuilder: (context, style, states) => const Icon(FIcons.calendar),
  enabled: true,
  onSaved: (date) {},
  onReset: () {},
  autovalidateMode: AutovalidateMode.onUnfocus,
  forceErrorText: null,
  errorBuilder: (context, error) => Text(error),
);

FDateField.input(...)

FDateField.input(
  control: FDateFieldControl.managed(initial: DateTime(2024, 1, 1)),
  style: (style) => style.copyWith(...),
  label: const Text('Input Date'),
  description: const Text('Enter a date'),
  textInputAction: TextInputAction.done,
  textAlign: TextAlign.start,
  textAlignVertical: TextAlignVertical.center,
  expands: false,
  onEditingComplete: () {},
  onSubmit: (date) {},
  mouseCursor: SystemMouseCursors.text,
  canRequestFocus: true,
  clearable: true,
  baselineInputYear: 2000,
  builder: (context, style, states, child) => child!,
  prefixBuilder: (context, style, states) => const Icon(FIcons.calendar),
  suffixBuilder: (context, style, states) => const Icon(FIcons.calendar),
  enabled: true,
  onSaved: (date) {},
  onReset: () {},
  autovalidateMode: AutovalidateMode.onUnfocus,
  forceErrorText: null,
  errorBuilder: (context, error) => Text(error),
);

Examples

Calendar Only

FDateField.calendar(
  label: const Text('Appointment Date'),
  description: const Text('Select a date for your appointment'),
);

Input Only

FDateField.input(
  label: const Text('Appointment Date'),
  description: const Text('Select a date for your appointment'),
);

Clearable

FDateField(
  control: FDateFieldControl.managed(initial: DateTime.now()),
  label: const Text('Appointment Date'),
  description: const Text('Select a date for your appointment'),
  clearable: true,
);

Custom Validation

FDateField(
  control: FDateFieldControl.managed(
    validator: (date) => date?.weekday == 6 || date?.weekday == 7 ? 'Date cannot be a weekend.' : null,
  ),
  label: const Text('Appointment Date'),
  description: const Text('Select a date for your appointment'),
);

Form

class FormDateFieldPage extends StatefulWidget {
  @override
  State<FormDateFieldPage> createState() => _FormDateFieldPageState();
}

class _FormDateFieldPageState extends State<FormDateFieldPage> {
  final _key = GlobalKey<FormState>();
  late final _startController = FDateFieldController(
    validator: (date) => switch (date) {
      null => 'Please select a start date',
      final date when date.isBefore(DateTime.now()) => 'Start date must be in the future',
      _ => null,
    },
  );

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

  @override
  Widget build(BuildContext context) => Form(
    key: _key,
    child: Column(
      children: [
        FDateField(
          control: FDateFieldControl.managed(controller: _startController),
          label: const Text('Start Date'),
          description: const Text('Select a start date'),
          autovalidateMode: AutovalidateMode.disabled,
        ),
        const SizedBox(height: 20),
        FDateField(
          control: FDateFieldControl.managed(
            validator: (date) => switch (date) {
              null => 'Please select an end date',
              final date when _startController.value != null && date.isBefore(_startController.value!) =>
                'End date must be after start date',
              _ => null,
            },
          ),
          label: const Text('End Date'),
          description: const Text('Select an end date'),
          autovalidateMode: AutovalidateMode.disabled,
        ),
        const SizedBox(height: 25),
        FButton(
          child: const Text('Submit'),
          onPress: () {
            if (_key.currentState!.validate()) {
              // Form is valid, process the dates
            }
          },
        ),
      ],
    ),
  );
}

On this page