Date Picker
A date field with a calendar popover.
use herogpui::components::date_picker::DatePicker;DatePicker on docs.rsSource at v0.14.0
Usage
Showing International Calendar, live: HeroGPUI compiled to WebAssembly. The canvas has no accessibility tree; each example's description and code below carry the same information.
The field and the popover grid share the locale override. Segment order follows that locale; selected values stay Gregorian ISO dates. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::DatePicker;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w(px(256.))
.gap(px(12.))
.children(vec![DatePicker::new(
self.demo_calendar("dp-indian", cx),
)
.label("Date")
.locale("en-US-u-ca-indian")
.into_any_element()])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::DatePicker;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w(px(256.))
.gap(px(12.))
.children(vec![DatePicker::new(
self.demo_calendar("dp-disabled", cx),
)
.label("Date")
.is_disabled(true)
.into_any_element()])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ActiveTheme, Date, DatePicker};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, px};
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
DatePicker::new(self.demo_calendar("dp-controlled", cx))
.label("Date")
.on_change(cx.listener(
|this, d: &Option<Date>, _, cx| {
this.cal_picked = *d;
cx.notify();
},
))
.into_any_element(),
para(
&match self.cal_picked {
Some(d) => format!("Value: {}", d.format_iso()),
None => "No value".to_owned(),
},
cx,
),
])Also calls para (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{Date, DatePicker};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w(px(256.))
.gap(px(12.))
.children(vec![DatePicker::new(
self.demo_calendar("dp-invalid", cx),
)
.label("Date")
// `minValue`/`maxValue` bound the calendar: everything
// outside the range is unselectable.
.min_value(Date::new(2025, 12, 1))
.max_value(Date::new(2026, 6, 30))
.is_invalid(true)
.into_any_element()])The trigger follows the operating system's regional date order, separators, and numeric padding. Its state and submitted value stay ISO-formatted. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::DatePicker;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
DatePicker::new(self.demo_calendar("dp-format", cx))
.label("Date")
.into_any_element(),
])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{Button, DatePicker, Form};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![Form::new()
.child(
DatePicker::new(self.demo_calendar("dp-form", cx))
.label("Start date"),
)
.child(Button::new("date-picker-form-submit").label("Save"))
.into_any_element()])A custom indicator replaces the default calendar glyph; this example uses a check without changing the trigger behavior. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ActiveTheme, DatePicker, icons};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
DatePicker::new(self.demo_calendar("dp-indicator", cx))
.label("Date")
.trigger_indicator(gpui::svg()
.size(px(16.))
.path(icons::CHECK)
.text_color(cx.colors().foreground)
.into_any_element())
.into_any_element(),
])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{Button, DatePicker};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let is_open = self.date_picker_open;
let render_props_gallery = cx.entity().downgrade();
gpui::div()
.flex()
.flex_col()
.w(px(256.))
.gap(px(12.))
.children(vec![DatePicker::new(
self.demo_calendar("dp-render-props", cx)
)
.is_open(is_open)
.is_required(true)
.content(move |state| {
let gallery = render_props_gallery.clone();
gpui::div()
.flex()
.flex_col()
.items_start()
.gap(px(8.))
.child(format!(
"{} · {} · {}",
if state.is_required {
"required"
} else {
"optional"
},
if state.is_invalid { "invalid" } else { "valid" },
if state.is_open { "open" } else { "closed" },
))
.child(
Button::new("date-picker-render-props-toggle")
.label(if state.is_open { "Close" } else { "Open" })
.on_press(move |_, _, cx| {
if let Some(gallery) = gallery.upgrade() {
gallery.update(cx, |gallery, cx| {
gallery.date_picker_open =
!gallery.date_picker_open;
cx.notify();
});
}
}),
)
.into_any_element()
})
.into_any_element()])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{Date, DatePicker};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let is_open = self.date_picker_open;
gpui::div()
.flex()
.flex_col()
.w(px(256.))
.gap(px(12.))
.children(vec![DatePicker::new(self.demo_calendar("dp-usage", cx))
// v3's Usage seeds the picker with `defaultValue`.
.default_value(Date::new(2025, 12, 25))
.label("Due date")
.is_open(is_open)
.on_open_change(cx.listener(|this, open: &bool, _, cx| {
this.date_picker_open = *open;
cx.notify();
}))
.on_change(cx.listener(
|this, d: &Option<Date>, _, cx| {
this.cal_picked = *d;
this.date_picker_open = false;
cx.notify();
},
))
.into_any_element()])The calendar popover accepts the shared 22-value placement vocabulary. Defaults to a centered bottom popover; this specimen opts into top placement. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{DatePicker, Placement};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w(px(256.))
.gap(px(12.))
.children(vec![
DatePicker::new(self.demo_calendar("dp-placement", cx))
.label("Top placement")
.placement(Placement::Top)
.default_open(true)
.into_any_element(),
])Helpers used by these examples
Plain functions over the public API, defined once here and copied with each example that calls them.
fn para(text: &str, cx: &App) -> gpui::AnyElement {
let colors = cx.colors();
gpui::div()
.text_size(px(14.5))
.line_height(px(24.))
.text_color(colors.foreground)
.max_w(px(720.))
.child(text.to_owned())
.into_any_element()
}Anatomy
Rust types
Date Picker is assembled from these builders. The API reference lists each one.
Customization
Shared appearance belongs on ThemeBuilder::components and .recipe("name"). Typed builders change how Date Picker looks at one call site. Every builder also carries sx for placement, width and flex: it takes GPUI's own styling methods and refines them over the component's root after the theme, so an instance override wins. Behaviour builders live in the API reference below.
Styling
| Method | Values | Description |
|---|---|---|
placement(Placement) | Placement | The full 22-value union renders through the shared vocabulary with default eight-pixel popover offset: physical and aligned spellings plus the logical start/end aliases, which share their left/right side's pixels in this LTR-only port. The centered bottom value matches default. |
// The one slot for caller-owned low-level styling: GPUI's
// styling methods, refined over the root element last.
.sx(|el| {
el.bg(gpui::rgba(0xffa500ff)) // background
.text_color(gpui::rgba(0x000000ff)) // text
.w(gpui::px(13.)) // size
.h(gpui::px(12.))
})API reference
Against HeroUI v3.2.6: 29 entries ported, 5 partial, 2 not ported. Partial rows are marked in the tables; entries not ported are listed under each table with the reason.
Builders
| Builder | Values | Default | Description |
|---|---|---|---|
value( | DateValue | | — | Seeds the controlled date into the caller-owned CalendarState on the first render. |
default_value( | DateValue | | — | Seeds the uncontrolled date once without fighting later edits. |
on_change( | Fn( | — | Reports valid field edits and calendar selections. |
is_open( | true | | — | Controls the calendar popover without mutating local open state. |
default_open( | true | | false | Seeds uncontrolled popover state. |
on_open_change( | Fn( | — | Reports trigger, selection, Escape, outside-press and focus-departure changes. |
is_disabled( | true | | false | Removes the field and trigger from interaction and form submission. |
is_read_only( | true | | false | Keeps the date focusable while suppressing edits, opening and selection. |
is_required( | true | | false | Blocks native form submission while empty and focuses the editable field. |
is_invalid( | true | | — | Forces invalid field and calendar state. |
validate(Partial | Fn( | — | A callback supplies one optional validation message; does not expose structured ValidationError object. |
validation_behavior( | ValidationBehavior:: | ValidationBehavior:: | Selects blocking native validation or non-blocking ARIA-style validation. |
validation_errors(Partial | string[] | — | Server messages take precedence and mark the field invalid; independently composed FieldError message content is unavailable. |
min_value( | DateValue | — | Earliest valid field and calendar date. |
max_value( | DateValue | — | Latest valid field and calendar date. |
is_date_unavailable( | Fn( | — | Rejects individual dates inside the range. |
first_day_of_week( | string | Weekday:: | The calendar grid defaults from the operating system's regional date preferences through CLDR week data; the local Weekday enum provides an explicit override. |
should_close_on_select(Partial | true | | true | The boolean form controls whether a calendar selection dismisses the popover; callback-valued policy is not represented. |
auto_focus( | true | | false | Focuses the editable date field on first render. |
name( | string | — | Submits the displayed date text under this name. |
content( | AnyElement | | — | Replacement content receives disabled, invalid, read-only, required, focus and open state. |
trigger_indicator( | AnyElement | AnyElement:: | Replaces the glyph inside the existing trigger geometry and behavior. |
placement( | Placement | Placement:: | The full 22-value union renders through the shared vocabulary with default eight-pixel popover offset: physical and aligned spellings plus the logical start/end aliases, which share their left/right side's pixels in this LTR-only port. The centered bottom value matches default. |
Not ported2 HeroUI entries not ported
| HeroUI v3 | Why it is not ported |
|---|---|
DatePicker.className / style | Browser styles and inline styles are unavailable. |
DatePicker.render | Root-element substitution has no GPUI equivalent. |
Parts
| Part | Description |
|---|---|
DatePicker | Root state owner and focus-within scope with a system-regionally formatted DateField. Each picker keeps its own CalendarState identity. |
DatePickerPartial | Separate keyboard and pointer action inside the date field suffix. |
DatePicker | Default or caller-supplied 16px trigger glyph. |
DatePickerPartial | Calendar overlay positioned by the shared Placement vocabulary. |
States
| State | Builder | Description |
|---|---|---|
Open | controlled/open overlay state | Mounts the calendar overlay and hands open state to replacement content. |
Focus within | close_on_blur focus scope | Tracks focus across the editable field, trigger and calendar. |
Focus visible | trigger focus ring | Draws the trigger ring and hands keyboard-visible root focus to replacement content. |
Disabled | is_disabled(bool) | Applies disabled opacity and removes editing, opening and submission. |
Read only | is_read_only(bool) | Keeps the field focusable while making field, trigger and calendar inert. |
Required | is_required(bool) | Marks the label and blocks empty native submission. |
Invalid | resolved DatePicker validity | Combines controlled, server, custom, syntax and date-constraint validation. |