DatePicker
A flexible date picker component with calendar interface that supports single date selection, date range selection, custom date formatting, disabled dates, and preset ranges.
Import
rust
use gpui_component::{
date_picker::{DatePicker, DatePickerState, DateRangePreset, DatePickerEvent},
calendar::{Date, Matcher},
};
Usage
Basic Date Picker
rust
let date_picker = cx.new(|cx| DatePickerState::new(window, cx));
DatePicker::new(&date_picker)
With Initial Date
rust
use chrono::Local;
let date_picker = cx.new(|cx| {
let mut picker = DatePickerState::new(window, cx);
picker.set_date(Local::now().naive_local().date(), window, cx);
picker
});
DatePicker::new(&date_picker)
Date Range Picker
rust
use chrono::{Local, Days};
// Range mode picker
let range_picker = cx.new(|cx| DatePickerState::range(window, cx));
DatePicker::new(&range_picker)
.number_of_months(2) // Show 2 months for easier range selection
// With initial range
let range_picker = cx.new(|cx| {
let now = Local::now().naive_local().date();
let mut picker = DatePickerState::new(window, cx);
picker.set_date(
(now, now.checked_add_days(Days::new(7)).unwrap()),
window,
cx,
);
picker
});
DatePicker::new(&range_picker)
.number_of_months(2)
With Custom Date Format
rust
let date_picker = cx.new(|cx| {
DatePickerState::new(window, cx)
.date_format("%Y-%m-%d") // ISO format
});
DatePicker::new(&date_picker)
// Other format examples:
// "%m/%d/%Y" -> 12/25/2023
// "%B %d, %Y" -> December 25, 2023
// "%d %b %Y" -> 25 Dec 2023
With Placeholder
rust
DatePicker::new(&date_picker)
.placeholder("Select a date...")
Cleanable Date Picker
rust
DatePicker::new(&date_picker)
.cleanable() // Shows clear button when date is selected
Different Sizes
rust
DatePicker::new(&date_picker).large()
DatePicker::new(&date_picker) // medium (default)
DatePicker::new(&date_picker).small()
Disabled State
rust
DatePicker::new(&date_picker).disabled(true)
Custom Appearance
rust
// Without default styling
DatePicker::new(&date_picker).appearance(false)
// Use in custom container
div()
.border_b_2()
.px_6()
.py_3()
.border_color(cx.theme().border)
.bg(cx.theme().secondary)
.child(DatePicker::new(&date_picker).appearance(false))
Date Restrictions
Disabled Weekends
rust
use gpui_component::calendar;
let date_picker = cx.new(|cx| {
DatePickerState::new(window, cx)
.disabled_matcher(vec![0, 6]) // Sunday=0, Saturday=6
});
DatePicker::new(&date_picker)
Disabled Date Range
rust
use chrono::{Local, Days};
let now = Local::now().naive_local().date();
let date_picker = cx.new(|cx| {
DatePickerState::new(window, cx)
.disabled_matcher(calendar::Matcher::range(
Some(now),
now.checked_add_days(Days::new(7)),
))
});
DatePicker::new(&date_picker)
Disabled Date Interval
rust
let date_picker = cx.new(|cx| {
DatePickerState::new(window, cx)
.disabled_matcher(calendar::Matcher::interval(
Some(now),
now.checked_add_days(Days::new(5))
))
});
DatePicker::new(&date_picker)
Custom Disabled Dates
rust
// Disable first 5 days of each month
let date_picker = cx.new(|cx| {
DatePickerState::new(window, cx)
.disabled_matcher(calendar::Matcher::custom(|date| {
date.day0() < 5
}))
});
DatePicker::new(&date_picker)
// Disable all Mondays
let date_picker = cx.new(|cx| {
DatePickerState::new(window, cx)
.disabled_matcher(calendar::Matcher::custom(|date| {
date.weekday() == chrono::Weekday::Mon
}))
});
Preset Ranges
Single Date Presets
rust
use chrono::{Utc, Duration};
let presets = vec![
DateRangePreset::single(
"Yesterday",
(Utc::now() - Duration::days(1)).naive_local().date(),
),
DateRangePreset::single(
"Last Week",
(Utc::now() - Duration::weeks(1)).naive_local().date(),
),
DateRangePreset::single(
"Last Month",
(Utc::now() - Duration::days(30)).naive_local().date(),
),
];
DatePicker::new(&date_picker)
.presets(presets)
Date Range Presets
rust
let range_presets = vec![
DateRangePreset::range(
"Last 7 Days",
(Utc::now() - Duration::days(7)).naive_local().date(),
Utc::now().naive_local().date(),
),
DateRangePreset::range(
"Last 30 Days",
(Utc::now() - Duration::days(30)).naive_local().date(),
Utc::now().naive_local().date(),
),
DateRangePreset::range(
"Last 90 Days",
(Utc::now() - Duration::days(90)).naive_local().date(),
Utc::now().naive_local().date(),
),
];
DatePicker::new(&date_picker)
.number_of_months(2)
.presets(range_presets)
Handle Date Selection Events
rust
let date_picker = cx.new(|cx| DatePickerState::new(window, cx));
cx.subscribe(&date_picker, |view, _, event, _| {
match event {
DatePickerEvent::Change(date) => {
match date {
Date::Single(Some(selected_date)) => {
println!("Single date selected: {}", selected_date);
}
Date::Range(Some(start), Some(end)) => {
println!("Date range selected: {} to {}", start, end);
}
Date::Range(Some(start), None) => {
println!("Range start selected: {}", start);
}
_ => {
println!("Date cleared");
}
}
}
}
});
Multiple Months Display
rust
// Show 2 months side by side (useful for date ranges)
DatePicker::new(&date_picker)
.number_of_months(2)
// Show 3 months
DatePicker::new(&date_picker)
.number_of_months(3)
Advanced Examples
Business Days Only
rust
use chrono::Weekday;
let business_days_picker = cx.new(|cx| {
DatePickerState::new(window, cx)
.disabled_matcher(calendar::Matcher::custom(|date| {
matches!(date.weekday(), Weekday::Sat | Weekday::Sun)
}))
});
DatePicker::new(&business_days_picker)
.placeholder("Select business day")
Date Range with Max Duration
rust
use chrono::Days;
let max_30_days_picker = cx.new(|cx| DatePickerState::range(window, cx));
cx.subscribe(&max_30_days_picker, |view, picker, event, _| {
match event {
DatePickerEvent::Change(Date::Range(Some(start), Some(end))) => {
let duration = end.signed_duration_since(*start).num_days();
if duration > 30 {
// Reset to start date only if range exceeds 30 days
picker.update(cx, |state, cx| {
state.set_date(Date::Range(Some(*start), None), window, cx);
});
}
}
_ => {}
}
});
DatePicker::new(&max_30_days_picker)
.number_of_months(2)
.placeholder("Select up to 30 days")
Quarter Presets
rust
use chrono::{NaiveDate, Datelike};
fn quarter_start(year: i32, quarter: u32) -> NaiveDate {
let month = (quarter - 1) * 3 + 1;
NaiveDate::from_ymd_opt(year, month, 1).unwrap()
}
fn quarter_end(year: i32, quarter: u32) -> NaiveDate {
let month = quarter * 3;
let start = NaiveDate::from_ymd_opt(year, month, 1).unwrap();
NaiveDate::from_ymd_opt(year, month, start.days_in_month()).unwrap()
}
let year = Local::now().year();
let quarterly_presets = vec![
DateRangePreset::range("Q1", quarter_start(year, 1), quarter_end(year, 1)),
DateRangePreset::range("Q2", quarter_start(year, 2), quarter_end(year, 2)),
DateRangePreset::range("Q3", quarter_start(year, 3), quarter_end(year, 3)),
DateRangePreset::range("Q4", quarter_start(year, 4), quarter_end(year, 4)),
];
DatePicker::new(&date_picker)
.presets(quarterly_presets)
API Reference
DatePickerState
Method | Description |
---|---|
new(window, cx) | Create a single date picker state |
range(window, cx) | Create a date range picker state |
date_format(format) | Set display format (default: "%Y/%m/%d") |
number_of_months(count) | Set calendar months to display (default: 1) |
disabled_matcher(matcher) | Set date disabling rules |
date() | Get current selected date |
set_date(date, window, cx) | Set selected date programmatically |
focus_handle(cx) | Get focus handle |
DatePicker
Method | Description |
---|---|
new(state) | Create date picker with state entity |
placeholder(text) | Set placeholder text |
cleanable() | Show clear button when date selected |
presets(presets) | Set quick selection presets |
number_of_months(count) | Set months to display (overrides state) |
appearance(bool) | Enable/disable default styling |
disabled(bool) | Set disabled state |
large() | Large size |
small() | Small size |
DateRangePreset
Method | Description |
---|---|
single(label, date) | Create single date preset |
range(label, start, end) | Create date range preset |
Date
Variant | Description |
---|---|
Single(Option<NaiveDate>) | Single date selection |
Range(Option<NaiveDate>, Option<NaiveDate>) | Date range selection |
Method | Description |
---|---|
format(format_str) | Format date(s) using chrono format string |
is_some() | Check if date is selected |
is_complete() | Check if selection is complete |
Matcher
Variant | Description |
---|---|
DayOfWeek(Vec<u32>) | Disable specific weekdays (0=Sunday, 6=Saturday) |
Interval(IntervalMatcher) | Disable dates outside interval |
Range(RangeMatcher) | Disable dates within range |
Custom(fn) | Custom disable function |
Method | Description |
---|---|
interval(before, after) | Create interval matcher |
range(from, to) | Create range matcher |
custom(fn) | Create custom matcher |
DatePickerEvent
Event | Description |
---|---|
Change(Date) | Date selection changed |
Format Strings
Common date format patterns using chrono format specifiers:
Format | Example Output |
---|---|
%Y-%m-%d | 2023-12-25 |
%m/%d/%Y | 12/25/2023 |
%d/%m/%Y | 25/12/2023 |
%B %d, %Y | December 25, 2023 |
%b %d, %Y | Dec 25, 2023 |
%d %b %Y | 25 Dec 2023 |
%A, %B %d, %Y | Monday, December 25, 2023 |
%Y 年 %m 月 %d 日 | 2023 年 12 月 25 日 |
Accessibility
- Full keyboard navigation with Tab and arrow keys
- Enter to open/confirm date selection
- Escape to close calendar or clear selection
- Delete/Backspace to clear selected date
- Clear focus indicators for all interactive elements
- Screen reader friendly with proper ARIA attributes
- Calendar navigation with Page Up/Down for months
- Home/End keys for week navigation
- Cleanable button accessible via keyboard
- Preset buttons fully keyboard accessible
Examples
Event Date Picker
rust
let event_date = cx.new(|cx| {
let mut picker = DatePickerState::new(window, cx)
.date_format("%B %d, %Y")
.disabled_matcher(calendar::Matcher::custom(|date| {
// Disable past dates
*date < Local::now().naive_local().date()
}));
picker
});
DatePicker::new(&event_date)
.placeholder("Choose event date")
.cleanable()
Booking System Date Range
rust
let booking_range = cx.new(|cx| DatePickerState::range(window, cx));
let booking_presets = vec![
DateRangePreset::range("This Weekend", /* weekend dates */),
DateRangePreset::range("Next Week", /* next week dates */),
DateRangePreset::range("This Month", /* this month dates */),
];
DatePicker::new(&booking_range)
.number_of_months(2)
.presets(booking_presets)
.placeholder("Select check-in and check-out dates")
Financial Period Selector
rust
let financial_period = cx.new(|cx| {
DatePickerState::range(window, cx)
.date_format("%Y-%m-%d")
});
DatePicker::new(&financial_period)
.number_of_months(3)
.presets(quarterly_presets)
.placeholder("Select reporting period")