| title |
description |
| DatePicker |
A date picker component for selecting single dates or date ranges with calendar interface. |
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
use gpui_component::{
date_picker::{DatePicker, DatePickerState, DateRangePreset, DatePickerEvent},
calendar::{Date, Matcher},
};
Usage
Basic Date Picker
let date_picker = cx.new(|cx| DatePickerState::new(window, cx));
DatePicker::new(&date_picker)
With Initial Date
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
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
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
DatePicker::new(&date_picker)
.placeholder("Select a date...")
Cleanable Date Picker
DatePicker::new(&date_picker)
.cleanable() // Shows clear button when date is selected
Different Sizes
DatePicker::new(&date_picker).large()
DatePicker::new(&date_picker) // medium (default)
DatePicker::new(&date_picker).small()
Disabled State
DatePicker::new(&date_picker).disabled(true)
Custom Appearance
// 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
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
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
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
// 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
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
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
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
// 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
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
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
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 日 |
Examples
Event Date Picker
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
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
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")