Pickers
Date, time, and date-range pickers all share a common structure: an editable / read-only text trigger field with an inline popover anchored below. All values flow through as UTC DateTime instances.
Live Example
Open the full route: Pickers.
DateTimePicker
Editable text field + popover. Drives mode (date / time / dateTime) to choose what the popover shows. The text field enforces the format via DateTimeInputFormatter so users can either type or pick.
DateTimePicker(
mode: DateTimePickerMode.dateTime,
value: selected,
onChanged: (dt) => setState(() => selected = dt), // dt is UTC
firstDate: DateTime(2020),
lastDate: DateTime(2030),
minuteStep: 5,
datePattern: 'MM/DD/YYYY', // default
timePattern: 'HH:mm', // default
showToday: true, // default — show Today quick-jump in date modes
)DateTimePickerMode
| Mode | Trigger pattern | Popover |
|---|---|---|
date | MM/DD/YYYY | Calendar only |
time | HH:mm | TimeScrollPicker only |
dateTime | MM/DD/YYYY HH:mm | Calendar + time scroll side-by-side |
CdxDateRangePicker
Range-specific variant. Read-only trigger displays MMM d, y - MMM d, y (formatted via FieldFormatter.instance.formatDate). The popover is a single-month calendar with shadcn-style range visuals: filled circles on start/end, light band between.
CdxDateRangePicker(
value: range, // DateTimeRange?
firstDate: DateTime(2020),
lastDate: DateTime(2030),
onChanged: (r) => setState(() => range = r),
hintText: 'Pick a date range',
)Two-tap selection model:
- First tap → start, end cleared
- Second tap → end (swapped if before start)
- Third tap → resets start
DateTimePopover
The popover content used by DateTimePicker (date / time / dateTime modes). Useful when you want to embed the picker UI without the text trigger.
DateTimePopover(
value: current,
showDate: true,
showTime: true,
onChanged: (dt) => store.setSchedule(dt),
firstDate: DateTime(2020),
lastDate: DateTime(2030),
minuteStep: 15,
showToday: true,
onTodaySelected: () => analytics.track('today_selected'),
)Calendar popovers
Two raw calendar popovers underlie the dateTime / range pickers:
| Widget | Selection | Use directly |
|---|---|---|
CdxSingleDatePopover | Single date — single tap commits, optional Today action via showToday / onTodayChanged | Custom date pickers |
CdxDateRangePopover | Two-tap range, with mid-range band visual | Custom range pickers |
Both share the same header (tappable month-year title opens a year grid) and weekday/day grid aesthetic.
TimeScrollPicker
iOS-style two-column scrollable time picker. Each column auto-centers the selection.
TimeScrollPicker(
hour: time.hour,
minute: time.minute,
minuteStep: 15, // snaps minutes to nearest valid step
onHourChanged: (h) => store.setHour(h),
onMinuteChanged: (m) => store.setMinute(m),
)Fixed at 120 px wide, expands to fill its parent's vertical constraint via Expanded.
TimeStepper
Compact ◀ 22 ▶ row with arrow buttons and a tappable middle that enters direct-edit mode. Mouse scroll wheel increments / decrements. Values wrap past min / max.
TimeStepper(
value: minutes,
min: 0,
max: 59,
step: 1,
onChanged: (v) => store.setMinutes(v),
)DateTimeInputFormatter
TextInputFormatter enforcing a date/time pattern. Auto-inserts separators (/, -, ., :, ), validates field ranges inline (e.g. month can only start with 0 or 1), rejects impossible dates (Feb 30), and exposes tryParse / format helpers.
| Token | Meaning |
|---|---|
DD | Day (01–31) |
MM | Month (01–12) |
YYYY | Year (4 digits) |
HH | Hour (00–23) |
mm | Minute (00–59) |
final formatter = DateTimeInputFormatter(pattern: 'YYYY-MM-DD HH:mm');
TextField(
inputFormatters: [formatter],
keyboardType: TextInputType.number,
);
final dt = formatter.tryParse('2026-04-18 14:30'); // local DateTime or null
final str = formatter.format(DateTime.now()); // '2026-04-18 14:30'UTC contract
Every picker emits UTC values via onChanged, and accepts UTC values as value. Internal display logic converts to local for the calendar / text trigger so users see their local date/time, but the round-trip is always UTC. Match this in your store: store UTC, display local through the picker.
Cross-links
- Overlays —
buildOverlayFollowerpositioning - Inputs — text-input formatting patterns
- Field Formatting —
FieldFormatterfor displaying formatted dates/times outside the picker