WFormDatePicker
A form-integrated date picker that wraps WDatePicker with Flutter's FormField. Provides native form validation, automatic error: state styling, and optional label, hint, and error message display.
- Basic Usage
- Constructor
- Props
- Form Validation
- Range Mode in Forms
- Date + Time in Forms
- Event Handling
- State Variants
- Styling Examples
- All Supported Classes
- Customizing Theme
- Related Documentation
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.
final _formKey = GlobalKey();
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',
onPressed: () {
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
WFormDatePicker({
Key? key,
// FormField params
FormFieldValidator? validator,
FormFieldSetter? onSaved,
AutovalidateMode? autovalidateMode,
bool enabled = true,
// WDatePicker params
DateTime? initialValue,
DateRange? initialRange,
WDatePickerMode mode = WDatePickerMode.single,
ValueChanged? onChanged,
ValueChanged? onRangeChanged,
DateTime? minDate,
DateTime? maxDate,
String? className,
String? placeholder,
Set? 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 text-xs mt-1',
String? hint,
String hintClassName = 'text-gray-500 text-xs mt-1',
})
Props
FormField Props
| Prop | Type | Default | Description |
|---|---|---|---|
validator |
FormFieldValidator |
null |
Validation function, receives DateTime? |
onSaved |
FormFieldSetter |
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 |
null |
Called on selection (single and dateTime modes) |
onRangeChanged |
ValueChanged |
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 |
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 text-xs mt-1' |
Wind classes for error message |
hint |
String? |
null |
Hint text displayed below the picker |
hintClassName |
String |
'text-gray-500 text-xs mt-1' |
Wind classes for hint text |
[!NOTE] When both an error and hint are present, the error message takes priority and the hint is hidden.
Form Validation
The validator function receives the currently selected DateTime? value. Return a String to show an error, or null if valid.
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:
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
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 internally tracks the range's start date for validation purposes. This means a simple null check still works as a "required" validator.
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);
}
},
)
[!NOTE] The
validatorreceives the range's startDateTime, not aDateRangeobject. For more complex range validation (e.g., minimum stay duration), use theonRangeChangedcallback to manage validation externally.
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.
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 behaviors carry over from the raw widget. The field revalidates on every time step, not only on the day tap, because onChanged fires on each one; 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.
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 |
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
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
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
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 text-xs mt-1
Hint (hintClassName)
Default: text-gray-500 text-xs mt-1
Customizing Theme
WFormDatePicker inherits all theme customization from WDatePicker. Override Tailwind color scales in WindThemeData to change selection colors, error states, and calendar chrome:
WindTheme(
data: WindThemeData(
colors: {
...WindThemeData.defaultColors,
'red': {
500: Color(0xFFEF4444), // Error border color
200: Color(0xFFFECACA), // Error ring color
},
},
),
child: MyApp(),
)
Related Documentation
- WDatePicker - The base date picker widget
- WFormInput - Form-integrated text input
- WFormSelect - Form-integrated dropdown
- WFormCheckbox - Form-integrated checkbox
- WPopover - The underlying overlay engine