Date Time Picker

Dropdown calendar with hour, minute, and second inputs, in 12 or 24-hour cycles.

Basic

.heex
<.date_time_picker name="scheduled_at" />

Label and help text

description renders above the field; help_text renders below it.

Required

We will send a confirmation email immediately after booking.

All times are in UTC.
.heex
<.date_time_picker
  name="appointment_at"
  label="Appointment time"
  sublabel="Required"
  description="We will send a confirmation email immediately after booking."
  help_text="All times are in UTC."
/>

Pre-selected value

Pass a NaiveDateTime or DateTime. Strings in ISO 8601 are accepted too.

.heex
<.date_time_picker name="kickoff_at" value={DateTime.utc_now()} />

Sizes

.heex
<.date_time_picker name="scheduled_at" size="xs" />
<.date_time_picker name="scheduled_at" size="sm" />
<.date_time_picker name="scheduled_at" size="md" />
<.date_time_picker name="scheduled_at" size="lg" />
<.date_time_picker name="scheduled_at" size="xl" />

Disabled

.heex
<.date_time_picker name="locked" value={DateTime.utc_now()} disabled />

Required selection

Set allow_deselect={false} to keep the value sticky once a date and time are picked.

.heex
<.date_time_picker
  name="contract_at"
  label="Sign-off time"
  value={DateTime.utc_now()}
  allow_deselect={false}
/>

Clearable

Set clearable to render a reset button inside the field. It only appears once a value is present, and clearing resets both the date and the time, dispatching a change event so phx-change bindings are notified.

.heex
<.date_time_picker name="reminder_at" label="Remind me at" value={DateTime.utc_now()} clearable />

Error state

.heex
<.date_time_picker
  name="deadline_at"
  label="Deadline"
  errors={["Please pick a time in the future"]}
/>

Leading icon

Use :inner_prefix to place an icon inside the toggle border.

.heex
<.date_time_picker name="meeting_at" placeholder="Pick a meeting time">
  <:inner_prefix>
    <.icon name="hero-clock" class="icon" />
  </:inner_prefix>
</.date_time_picker>

12-hour and 24-hour

hour_cycle controls the time interface. h12 shows an AM/PM selector; h23 uses a 24-hour clock.

.heex
<.date_time_picker name="meeting_at" hour_cycle="h12" />
<.date_time_picker name="meeting_at" hour_cycle="h23" />

Custom display format

Pass a strftime pattern to control how the selected value renders in the toggle.

.heex
<.date_time_picker
  name="event_at"
  value={DateTime.utc_now()}
  display_format="%B %-d, %Y at %I:%M %p"
/>

Min and max

Constrain the selectable range. Calendar navigation buttons disable past the boundaries; the time inputs remain free.

.heex
<.date_time_picker
  name="window_at"
  min={Date.utc_today()}
  max={Date.add(Date.utc_today(), 14)}
/>

Weekdays only

Use the :weekends shortcut to disable Saturdays and Sundays. Other shortcuts and tuple patterns work the same as on date_picker.

.heex
<.date_time_picker
  name="business_meeting_at"
  disabled_dates={[:weekends]}
/>

Month and year dropdowns jump across long horizons in one click.

.heex
<.date_time_picker
  name="historical_at"
  navigation="select"
  min={~D[2000-01-01]}
  max={Date.utc_today()}
/>

Preset shortcuts

Render a sidebar of one-click jumps next to the calendar. The active preset highlights when it matches the current selection.

.heex
<.date_time_picker
  name="reminder_at"
  presets={[
    {"Today", Date.utc_today()},
    {"Tomorrow", Date.add(Date.utc_today(), 1)},
    {"In a week", Date.add(Date.utc_today(), 7)},
    {"In a month", Date.shift(Date.utc_today(), month: 1)}
  ]}
/>

Confirm mode

Set close="confirm" to show Cancel and Apply buttons. The value commits only on Apply, so date and time can be tweaked together before saving.

.heex
<.date_time_picker name="confirmed_at" close="confirm" />

German locale

locale drives weekday and month names plus defaults for week start and hour cycle. German pulls in h23 and a Monday week start automatically.

.heex
<.date_time_picker
  name="termin_at"
  label="Termin"
  placeholder="Termin auswaehlen"
  locale="de"
/>

Form integration

Changes: %{}
.heex
<.form :let={f} for={@form} phx-change="validate">
  <.date_time_picker field={f[:datetime]} />
</.form>
.ex
def handle_event("validate", %{"data" => _params}, socket) do
  # Re-run validation and reassign the form
  {:noreply, socket}
end