date_picker_form_field 0.2.1
date_picker_form_field: ^0.2.1 copied to clipboard
Locale-aware date form field with a calendar picker and typed manual entry in the local date format
date_picker_form_field #
An accessible, locale-adaptive date input field for Flutter that bridges keyboard data entry with an intuitive graphical calendar picker.
DatePickerFormField solves the classic user experience dilemma between typing dates quickly and choosing dates from a calendar. It dynamically formats input as the user types according to the active locale's natural date pattern (e.g. DD/MM/YYYY, MM/DD/YYYY, or YYYY-MM-DD), supports direct keyboard entry of date separators (/, ., -), and offers seamless adaptive popup calendar selection (Material and Cupertino).
| Date of Birth | Language Switcher |
|---|---|
Key Architectural Strengths #
- Dynamic, Locale-Adaptive Masking with Typed Separator Support (
DateInputFormatter):- Unlike rigid fixed-mask formatters,
DateInputFormatterinspectsDateFormat.yMdfor the active locale at runtime to determine the true localized ordering of Day, Month, and Year as well as the regional separator (/,-,.). - Users can type numbers continuously or type separators directly from their keyboard; typed separators show immediately without waiting for subsequent digits, and single-digit day or month entries followed by a separator are automatically zero-padded (
03/). - Automatically matches and adjusts placeholder hints (e.g.
DD/MM/YYYYin the UK,MM/DD/YYYYin the US,YYYY-MM-DDin Canada/Japan).
- Unlike rigid fixed-mask formatters,
- Intelligent Cursor & Separator Navigation:
- Purpose-built editing logic handles typing, digit insertions, and backspacing across separators gracefully: backspacing over a separator removes the preceding digit cleanly without breaking cursor placement or trapping user focus.
- Adaptive Platform Date Picking (
AdaptiveDatePickerProvider):- Automatically chooses the native design idiom for the current platform: Cupertino date picker in a modal popup on iOS and macOS, and Material
DatePickerDialogon Android and desktop platforms. - Pluggable layer of indirection: inject a custom
pickerProviderdirectly intoDatePickerFormFieldor provide anAdaptiveDatePickerProviderhigher in the widget tree.
- Automatically chooses the native design idiom for the current platform: Cupertino date picker in a modal popup on iOS and macOS, and Material
- Unified Dual-Mode Workflow:
- Users can either type digits directly (with or without separators) or tap the calendar icon to select from the platform picker.
- Date choices in either mode keep the text field and validation state perfectly synchronized.
- Validation-Ready State Contract:
- The
onDateChangedcallback provides a structuredDateInputValue(rawText: ..., parsedDate: ...). parsedDateevaluates tonullif the date is incomplete, syntactically invalid (e.g. February 30th), or outside the allowablefirstDateandlastDateboundaries, enabling instant integration withFormzor FlutterFormvalidation.
- The
- Enterprise Reliability & Testability:
- Provides exported static keys (
textInputKey,launchDatePickerKey) for deterministic end-to-end testing. - Backed by comprehensive test suites with >99% code coverage.
- Provides exported static keys (
Features #
- Locale-Aware Formatting: Dynamically formats date components based on the user's regional preferences.
- Typed Separator Entry: Direct keyboard typing of date separators (
/,.,-) with instant feedback and auto-padding for single digits. - Adaptive Platform Picking: Seamless Cupertino picker on iOS/macOS and Material date picker dialog on Android/desktop, plus support for custom
AdaptiveDatePickerProviders. - Dual Input Modes: Fluid keyboard entry alongside standard graphical calendar picking.
- Strict Range Clamping: Enforces configurable
firstDateandlastDateboundaries. - Clean Event Lifecycle: Dedicated callbacks for
onDateChanged,onPickDate,onEditText,onFieldSubmitted, andonEditingComplete. - Form-Ready Validation: Typed
validatorandonSavedcallbacks that receive the parsedDateTime, integrating withForm.validate()and form-levelAutovalidateMode.
Getting Started #
Add date_picker_form_field to your pubspec.yaml:
dependencies:
date_picker_form_field: ^0.2.1
UI library: this package is built on
material_ui, the official Flutter Material library, and its API acceptsmaterial_uitypes such asInputDecoration. Importpackage:material_ui/material_ui.dartin code that constructs those arguments: it exports distinct types that are not assignable to or from the copies exported bypackage:flutter/material.dart.
Localization setup #
Initialize date formatting before the first frame, so that typed input is parsed and re-formatted with the pattern of the active locale:
import 'package:intl/date_symbol_data_local.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await initializeDateFormatting();
runApp(const MyApp());
}
Then configure your MaterialApp with the localization plumbing from
saible_consulting_core:
import 'package:material_ui/material_ui.dart';
import 'package:saible_consulting_core/saible_consulting_core.dart';
MaterialApp(
supportedLocales: SaibleLocalizations.supportedLocales,
localizationsDelegates: SaibleLocalizations.localizationsDelegates,
home: const MyFormPage(),
);
Migrating from package:flutter/material.dart #
material_ui is the Material library that used to ship inside
package:flutter/material.dart, so migration is mostly mechanical - the bundled
data-driven fix rewrites the imports for you:
dart fix --apply --code=migrate_design_widgets
Two things then need attention. Import package:material_ui/material_ui.dart
wherever you construct material_ui types (such as InputDecoration), as
described above - and make sure the localization delegates come from
material_ui too. material_ui widgets never read the legacy
GlobalMaterialLocalizations, GlobalCupertinoLocalizations or
GlobalWidgetsLocalizations classes from package:flutter_localizations, which
is why SaibleLocalizations.localizationsDelegates (shown above) pairs the
country names with material_ui's own Material, Cupertino and Widgets
delegates. Use the generated CountryLocalizations.localizationsDelegates only
while parts of your app still build with package:flutter/material.dart.
If a dependency or subtree still imports package:flutter/material.dart, use
MaterialUiCompatibilityBridge to bridge ThemeData and
MaterialLocalizations for it - app-wide through MaterialApp.builder, or
around the individual subtree:
MaterialApp(
builder: (context, child) => MaterialUiCompatibilityBridge(child: child!),
home: const MyScreen(),
);
The bridge is a temporary migration aid (deprecated in material_ui 1.5.0 and
scheduled for removal in a future release), so migrate the legacy dependency
rather than shipping it long term.
Usage #
Basic Example #
import 'package:material_ui/material_ui.dart';
import 'package:date_picker_form_field/date_picker_form_field.dart';
class DateOfBirthExample extends StatefulWidget {
const DateOfBirthExample({super.key});
@override
State<DateOfBirthExample> createState() => _DateOfBirthExampleState();
}
class _DateOfBirthExampleState extends State<DateOfBirthExample> {
DateTime? _selectedDate;
@override
Widget build(BuildContext context) {
return DatePickerFormField(
initialDate: DateTime(1995, 6, 15),
firstDate: DateTime(1900),
lastDate: DateTime.now(),
decoration: const InputDecoration(
labelText: 'Date of Birth',
border: OutlineInputBorder(),
),
onDateChanged: (value) {
setState(() {
_selectedDate = value.parsedDate;
});
print('Typed: ${value.rawText}, Valid Date: ${value.parsedDate}');
},
onPickDate: (pickedDate) {
print('Selected from calendar: $pickedDate');
},
);
}
}
Standalone DateInputFormatter Usage #
You can also use the formatter independently on any standard Flutter TextFormField:
import 'package:material_ui/material_ui.dart';
import 'package:date_picker_form_field/presentation/date_input_formatter.dart';
final formatter = DateInputFormatter(locale: 'en_GB');
TextFormField(
inputFormatters: [formatter],
decoration: InputDecoration(
hintText: formatter.hintText, // "DD/MM/YYYY"
),
);
Adaptive Date Picker & Custom Providers #
By default, DatePickerFormField automatically adapts to the host platform, displaying a Cupertino date picker in a modal popup on iOS and macOS, and a Material date picker dialog on Android, Linux, and Windows.
To override the platform default or plug in a custom date picker implementation, supply a custom pickerProvider:
import 'package:date_picker_form_field/date_picker_form_field.dart';
DatePickerFormField(
decoration: const InputDecoration(labelText: 'Birth Date'),
// Explicitly select Cupertino, Material, or a custom AdaptiveDatePickerProvider:
pickerProvider: CupertinoDatePickerProvider(),
onPickDate: (date) => print('Picked: $date'),
)
Form Validation #
validator and onSaved plug the field into a Form and receive the parsed
DateTime - null while the input is empty, incomplete, syntactically invalid
or outside firstDate/lastDate:
final formKey = GlobalKey<FormState>();
DateTime? dateOfBirth;
Form(
key: formKey,
child: DatePickerFormField(
firstDate: DateTime(1900),
lastDate: DateTime.now(),
decoration: const InputDecoration(labelText: 'Date of Birth'),
validator: (date) => date == null ? 'Enter a valid date' : null,
onSaved: (date) => dateOfBirth = date,
),
);
if (formKey.currentState!.validate()) {
formKey.currentState!.save();
print(dateOfBirth); // e.g. "1995-06-15 00:00:00.000"
}
The validator runs whenever the enclosing Form validates - through
FormState.validate() or a form-level AutovalidateMode - and sees the same
parsed value that onDateChanged reports, whether it was typed or picked from
the calendar dialog.
Testing #
DatePickerFormField exposes stable testing keys for automation:
DatePickerFormField.textInputKey: Key for the dateTextFormField.DatePickerFormField.launchDatePickerKey: Key for the calendar picker launcher icon button.
Example widget test:
// Type a date (with or without separators)
await tester.enterText(find.byKey(DatePickerFormField.textInputKey), '15/06/1995');
await tester.pumpAndSettle();
// Or tap the calendar icon to open the adaptive picker
await tester.tap(find.byKey(DatePickerFormField.launchDatePickerKey));
await tester.pumpAndSettle();
How this compares #
Alternative pub.dev packages, with their like counts, 30-day downloads and latest releases as of 1 October 2026:
| Package | Likes | Downloads | Latest | Trade-offs |
|---|---|---|---|---|
date_field |
139 | 905 | 7.0.0 (Sep 2026) | A well-maintained DateTimeFormField wrapping platform pickers (Material and Cupertino) with date, time or date-and-time modes. However, its value always comes from a picker dialog or sheet: there is no keyboard-first entry, no typed separator input, and no locale-driven input mask. |
Hand-rolled TextFormField + showDatePicker |
- | - | - | Zero extra dependencies, but you implement adaptive platform indirection, locale masking, keyboard separator entry and backspacing, parsing, range clamping and the validation contract yourself. |
Pick date_picker_form_field when you want DD/MM/YYYY-style keyboard entry driven
by the active locale with typed separator support and adaptive platform calendar
pickers (Material on Android/desktop, Cupertino on iOS/macOS, or custom providers)
in the same field, with the parsed DateTime (or null) handed to your Form
through validator and onSaved.
Additional Information #
- Source code: GitHub Repository
- Issue tracker: File bugs or feature requests via GitHub Issues.
- License: See LICENSE for details.