Skip to content

WFormDatePicker

View raw .md

A form-integrated date picker that wraps WDatePicker with Flutter's FormField<DateTime>. Provides native form validation, automatic error: state styling, and optional label, hint, and error message display.

On this page
Preview forms/form_date_picker_basic A live demo of this example follows. form_date_picker_basic.dart View source Open demo
dart
WFormDatePicker(
  label: 'Birth Date',
  hint: 'We need your date of birth for verification',
  className: 'p-3 border border-gray-300 rounded-lg error:border-red-500',
  validator: (value) => value == null ? 'Please select a date' : null,
  onChanged: (date) => print('Selected: $date'),
)

Basic Usage#

WFormDatePicker works inside a Flutter Form widget. It renders a vertical layout with an optional label above the date picker and error/hint text below.

dart
final _formKey = GlobalKey<FormState>();

Form(
  key: _formKey,
  child: Column(
    children: [
      WFormDatePicker(
        label: 'Event Date',
        className: 'p-3 border rounded-lg error:border-red-500',
        validator: (date) => date == null ? 'Date is required' : null,
        onChanged: (date) => _eventDate = date,
      ),
      WButton(
        className: 'mt-4 bg-blue-500 text-white px-4 py-2 rounded-lg',
        onTap: () {
          if (_formKey.currentState!.validate()) {
            _formKey.currentState!.save();
          }
        },
        child: WText('Submit'),
      ),
    ],
  ),
)

When validation fails, the widget automatically adds the error state to the inner WDatePicker, activating any error: prefixed classes.

Constructor#

dart
WFormDatePicker({
  Key? key,
  // FormField params
  FormFieldValidator<DateTime>? validator,
  FormFieldSetter<DateTime>? onSaved,
  AutovalidateMode? autovalidateMode,
  bool enabled = true,
  // WDatePicker params
  DateTime? initialValue,
  DateRange? initialRange,
  WDatePickerMode mode = WDatePickerMode.single,
  ValueChanged<DateTime>? onChanged,
  ValueChanged<DateRange>? onRangeChanged,
  DateTime? minDate,
  DateTime? maxDate,
  String? className,
  String? placeholder,
  Set<String>? states,
  DateDisplayFormat? displayFormat,
  // dateTime mode params, forwarded to WDatePicker
  int minuteStep = 5,
  String timeLabel = 'Time',
  String doneLabel = 'Done',
  // Form wrapper params
  String? label,
  String labelClassName = 'text-sm font-medium text-gray-700 dark:text-gray-300 mb-1',
  bool showError = true,
  String errorClassName = 'text-red-500 dark:text-red-400 text-xs mt-1',
  String? hint,
  String hintClassName = 'text-gray-500 dark:text-gray-400 text-xs mt-1',
})

Props#

FormField Props#

Prop Type Default Description
validator FormFieldValidator<DateTime>? null Validation function, receives DateTime?
onSaved FormFieldSetter<DateTime>? null Called when form is saved
autovalidateMode AutovalidateMode? null When to auto-validate
enabled bool true Whether the picker is interactive
initialValue DateTime? null Initial selected instant (single and dateTime modes; carries the time of day in dateTime). Seeds the field's state on first build only, as FormField does: changing it later does not move an already-picked value

Date Picker Props#

Prop Type Default Description
mode WDatePickerMode single Selection mode: single, range or dateTime
initialRange DateRange? null Initial date range (range mode)
onChanged ValueChanged<DateTime>? null Called on selection (single and dateTime modes)
onRangeChanged ValueChanged<DateRange>? null Called on range selection (range mode)
minDate DateTime? null Earliest selectable date
maxDate DateTime? null Latest selectable date
className String? null Wind utility classes for the trigger
placeholder String? null Placeholder text (defaults to 'Select date')
states Set<String>? null Custom states for dynamic styling
displayFormat DateDisplayFormat? null Custom date display format function
minuteStep int 5 Minutes each step control moves, forwarded to the picker (dateTime mode only)
timeLabel String 'Time' Label above the time row, forwarded to the picker (dateTime mode only)
doneLabel String 'Done' Confirm control text that closes the popover, forwarded to the picker (dateTime mode only)

Layout Props#

Prop Type Default Description
label String? null Label text displayed above the picker
labelClassName String 'text-sm font-medium text-gray-700 dark:text-gray-300 mb-1' Wind classes for the label
showError bool true Whether to display validation error text
errorClassName String 'text-red-500 dark:text-red-400 text-xs mt-1' Wind classes for error message
hint String? null Hint text displayed below the picker
hintClassName String 'text-gray-500 dark:text-gray-400 text-xs mt-1' Wind classes for hint text

Form Validation#

The validator function receives the currently selected DateTime? value. Return a String to show an error, or null if valid.

dart
WFormDatePicker(
  label: 'Departure Date',
  className: 'p-3 border rounded-lg error:border-red-500 error:bg-red-50',
  validator: (date) {
    if (date == null) return 'Please select a departure date';
    if (date.isBefore(DateTime.now())) return 'Date must be in the future';
    return null;
  },
)

Auto-Validation#

Use autovalidateMode to validate as the user interacts:

dart
WFormDatePicker(
  label: 'Start Date',
  autovalidateMode: AutovalidateMode.onUserInteraction,
  className: 'p-3 border rounded-lg error:border-red-500',
  validator: (date) => date == null ? 'Required' : null,
)

Using onSaved#

dart
DateTime? _savedDate;

WFormDatePicker(
  label: 'Meeting Date',
  className: 'p-3 border rounded-lg',
  onSaved: (date) => _savedDate = date,
  validator: (date) => date == null ? 'Required' : null,
)

Range Mode in Forms#

In range mode, the FormField<DateTime> internally tracks the range's start date for validation purposes. This means a simple null check still works as a "required" validator.

Preview forms/form_date_picker_range A live demo of this example follows. form_date_picker_range.dart View source Open demo
dart
WFormDatePicker(
  label: 'Trip Dates',
  mode: WDatePickerMode.range,
  initialRange: null,
  className: 'p-3 border rounded-lg error:border-red-500',
  placeholder: 'Select check-in / check-out',
  validator: (date) => date == null ? 'Please select your trip dates' : null,
  onRangeChanged: (range) {
    if (range.isComplete) {
      _calculateTripDuration(range);
    }
  },
)

Date + Time in Forms#

With mode: WDatePickerMode.dateTime the field holds a full DateTime carrying the picked hour and minute, so a validator can compare times of day rather than just checking for null. minuteStep, timeLabel, and doneLabel are forwarded to WDatePicker unchanged.

Preview widgets/date_picker_datetime A live demo of this example follows. date_picker_datetime.dart View source Open demo
dart
WFormDatePicker(
  mode: WDatePickerMode.dateTime,
  label: 'Call with the customer',
  hint: 'Office hours run 09:00 to 18:00',
  minuteStep: 15,
  doneLabel: 'Confirm',
  className: 'p-3 border rounded-lg error:border-red-500',
  autovalidateMode: AutovalidateMode.onUserInteraction,
  validator: (value) {
    if (value == null) return 'Pick a date and a time';
    if (value.hour < 9 || value.hour >= 18) {
      return 'Office hours run 09:00 to 18:00';
    }
    return null;
  },
)

Two behaviours carry over from the raw widget. Once a day is picked, every time step updates the field value, not only the day tap, because onChanged fires on each one; the validator runs on those changes when autovalidateMode is always or onUserInteraction (as above), when an enclosing Form sets its own mode, and on validate(); AutovalidateMode.onUnfocus validates on focus loss instead, not on each change; and initialValue seeds the field on first build only, the way FormField does, so changing it later does not move an already-picked value.

Event Handling#

onChanged and onRangeChanged fire alongside the form state updates. The FormFieldState is updated automatically; you don't need to call didChange yourself.

dart
WFormDatePicker(
  label: 'Appointment',
  onChanged: (date) {
    // FormField state is already updated at this point
    _loadAvailableSlots(date);
  },
)

State Variants#

WFormDatePicker inherits all state variants from WDatePicker and adds the error state automatically when validation fails.

State Activated When
hover: Mouse hovers over the trigger
focus: Calendar popover is open
open: Calendar popover is open (alias)
disabled: enabled is false
selected: A date or range has been selected
error: Form validation has failed
dart
WFormDatePicker(
  label: 'Date',
  className: 'p-3 border border-gray-300 rounded-lg '
      'hover:border-blue-400 '
      'focus:border-blue-500 focus:ring-2 focus:ring-blue-200 '
      'error:border-red-500 error:ring-2 error:ring-red-200 '
      'disabled:opacity-50 disabled:bg-gray-100',
  validator: (date) => date == null ? 'Required' : null,
)

Styling Examples#

Standard Form Field#

dart
WFormDatePicker(
  label: 'Date of Birth',
  hint: 'You must be at least 18 years old',
  className: 'w-full p-3 border border-gray-300 rounded-lg '
      'focus:border-blue-500 focus:ring-2 focus:ring-blue-200 '
      'error:border-red-500',
  maxDate: DateTime.now().subtract(const Duration(days: 365 * 18)),
  validator: (date) => date == null ? 'Date of birth is required' : null,
)

Dark Mode Ready#

dart
WFormDatePicker(
  label: 'Schedule',
  labelClassName: 'text-sm font-medium text-gray-700 dark:text-gray-300',
  className: 'p-3 bg-white dark:bg-gray-800 '
      'border border-gray-300 dark:border-gray-600 rounded-lg '
      'hover:border-blue-400 dark:hover:border-blue-500 '
      'error:border-red-500 dark:error:border-red-400',
  errorClassName: 'text-red-500 dark:text-red-400 text-xs mt-1',
  validator: (date) => date == null ? 'Required' : null,
)

Minimalist#

dart
WFormDatePicker(
  label: 'When',
  labelClassName: 'text-xs text-gray-500 uppercase tracking-wider',
  className: 'border-b border-gray-200 py-2 rounded-none '
      'focus:border-blue-500 error:border-red-500',
  hintClassName: 'text-gray-400 text-xs mt-0.5',
  hint: 'Optional',
)

All Supported Classes#

Trigger (className)#

All Wind utility classes work on the trigger container. The most commonly used:

Category Examples
Background bg-white, bg-gray-50, dark:bg-gray-800
Border border, border-gray-300, rounded-lg
Padding p-3, px-4, py-2
Sizing w-full, w-64
Ring ring-2, ring-blue-200
Shadow shadow-sm
State prefixes hover:, focus:, disabled:, selected:, error:, dark:

Label (labelClassName)#

Default: text-sm font-medium text-gray-700 dark:text-gray-300 mb-1

Error (errorClassName)#

Default: text-red-500 dark:text-red-400 text-xs mt-1

Hint (hintClassName)#

Default: text-gray-500 dark:text-gray-400 text-xs mt-1

Customizing Theme#

WFormDatePicker inherits all theme customisation from WDatePicker. Override Tailwind colour scales in WindThemeData to change selection colours, error states, and calendar chrome. The colours you pass merge over the defaults by name: a name you supply replaces that whole palette, so list every shade you use.

dart
WindTheme(
  data: WindThemeData(
    colors: {
      'red': MaterialColor(0xFFEF4444, {
        200: Color(0xFFFECACA), // Error ring color
        400: Color(0xFFF87171), // Dark mode error text (errorClassName)
        500: Color(0xFFEF4444), // Error border and error text color
      }),
    },
  ),
  child: MyApp(),
)
esc

Search index did not load.

No match for "".

Try a class like rounded-lg or a widget like WButton.