DateRangePicker

DateRangePicker is a convenience wrapper for two coordinated DatePicker instances.
Use it when the product question is "from when to when?" rather than "which single day?" Typical examples are reporting ranges, booking windows, and filter panels.

Example

use chrono::NaiveDate;
use fission::prelude::*;
use std::sync::Arc;

let widget: Widget = DateRangePicker {
id_start: WidgetId::explicit("range_start"),
id_end: WidgetId::explicit("range_end"),
start: view.state().range_start,
end: view.state().range_end,
is_start_open: view.state().range_start_open,
is_end_open: view.state().range_end_open,
on_change: Some(Arc::new(move |start: Option<NaiveDate>, end: Option<NaiveDate>| ActionEnvelope {
    id: set_range_id,
    payload: serde_json::to_vec(&SetDateRange { start, end }).unwrap(),
})),
on_toggle_start: Some(toggle_start_action),
on_toggle_end: Some(toggle_end_action),
on_close_start: Some(close_start_action),
on_close_end: Some(close_end_action),
}
.into();
This keeps the whole interaction inside the normal state loop: each side has explicit open state, and the reducer stays responsible for validating the final range.

Field table

Field
Type
Meaning
Notes / default behavior
id_start
WidgetId
Stable identity for the start-date trigger.
Required.
id_end
WidgetId
Stable identity for the end-date trigger.
Required.
start
Option<NaiveDate>
Current start date.
Controlled by app state.
end
Option<NaiveDate>
Current end date.
Controlled by app state.
is_start_open
bool
Whether the start picker popup is open.
Controlled by app state.
is_end_open
bool
Whether the end picker popup is open.
Controlled by app state.
on_change
Option<Arc<dyn Fn(Option<NaiveDate>, Option<NaiveDate>) -> ActionEnvelope + Send + Sync>>
Closure that receives the updated pair.
Called when either side changes.
on_toggle_start
Option<ActionEnvelope>
Action for opening or toggling the start picker.
Defaults to None.
on_toggle_end
Option<ActionEnvelope>
Action for opening or toggling the end picker.
Defaults to None.
on_close_start
Option<ActionEnvelope>
Explicit close action for the start picker.
Defaults to None.
on_close_end
Option<ActionEnvelope>
Explicit close action for the end picker.
Defaults to None.

Value model and validation

The widget only helps present the two pickers together. It does not decide whether the end date must be after the start date, whether empty values are allowed, or whether the two dates should snap to preset windows. Those rules belong in your reducer or validation layer.
A common pattern is to accept either side individually while the user is editing, then validate the pair before submitting or querying.

Specific advice

Keep the real range in state as dates, not formatted strings. Also think about what should happen when a user picks an end date earlier than the start date. Some products swap them automatically. Others keep the invalid state visible until the user fixes it. Pick one behavior intentionally and test it.

Production checklist

For DateRangePicker, review the fields that change behavior before treating the widget as finished: id_start, id_end, start, end, is_start_open, is_end_open. The goal is to make the product rule visible in state and actions, not hidden inside ad-hoc construction code.
Bind on_change, on_toggle_start to explicit reducer actions and test that the reducer handles unavailable, duplicate, or invalid input safely.
Check the semantics tree for the user-facing label or role that makes this widget understandable without relying only on pixels.
Add at least one component or harness test that confirms the visible text, semantic role, action dispatch, and layout constraint that matter for this widget in context.
If a screen starts repeating the same DateRangePicker setup, extract a named component around this widget. That keeps the reference API small while making product code easier to read and safer for generated code to copy.
DatePicker, TimePicker, FormControl, and Popover.
Fission
A cross-platform, GPU-accelerated user interface framework for Rust. MIT licensed.
Copyright (c) 2026 Fission
Ready to use today. Widget APIs are expected to remain stable; some runtime and shell APIs may change before 1.0.0.
Fission 0.7.0