HEEx components for locale-aware date form input.
Provides date_input/1, date_range_input/1, and
date_range_picker/1. Built on calendrical for
multi-calendar parsing (Gregorian, Buddhist, Japanese,
Islamic, Persian, Hebrew, ROC, …).
Setup
Add the JS hooks in your assets/js/app.js:
import Hooks from "localize_datetime_inputs"
let liveSocket = new LiveSocket("/live", Socket, {
hooks: {
DatePicker: Hooks.DatePicker,
DateRangePicker: Hooks.DateRangePicker
}
})Tolerance of invalid input
These components sit on the render path and never raise on bad input — the page always renders. Specifically:
Unknown
:locale— formatting falls back to whateverLocalize.Date.to_string/2returns; on failure the cell renders the ISO-8601 form of the date (2026-05-17).Unknown
:calendar— date conversion uses a tolerantDate.convert/2; on failure the date is kept in its original calendar (typicallyCalendar.ISO) and rendered using whatever pattern lookup succeeds.Blank or unparseable
value— the visible text input renders empty; the hidden ISO carrier stays empty.Localize.Inputs.Date.Parser.parse_date/2returns{:ok, nil}for blanks and{:error, %Calendrical.DateParseError{}}for garbage, never raises.date_range_input/1child field atoms — derives{field}_fromand{field}_toviaString.to_existing_atom/1. The atom must already exist (it does, because your changeset/schema defines it for form parsing); if it doesn't, anArgumentErrorsurfaces at render time and points at the missing field.DatePickerLivemalformed cursor / month — the server-rendered grid uses tolerantsafe_convert/2andsafe_build_date/4helpers. An invalid year/month combo for the target calendar falls back to today rather than 500ing the LiveView.
Summary
Functions
Locale-aware date input with a popup calendar grid.
Locale-aware date-range input.
Locale-aware date-range input with a unified popup
calendar (click start, then click end inside the same
grid). Pairs with RangePicker JS hook.
Functions
Locale-aware date input with a popup calendar grid.
Renders a text input that accepts the locale's CLDR date
patterns plus ISO-8601, paired with a calendar-icon trigger
that opens a Gregorian month grid for picking. Selecting a
day fills the text input (locale-formatted) and a hidden
sibling input (ISO wire format). On submit the form
receives params[field] as "YYYY-MM-DD".
Server-side, parse with Localize.Inputs.Date.Parser.parse_date/2
or Calendrical.Date.parse/2.
Multi-calendar parsing works (Buddhist, Islamic, Japanese, etc.) — the user can type in their locale's calendar representation and the server parses correctly. The popup grid renders in Gregorian; non-Gregorian grid rendering is a follow-on enhancement.
Attributes
:form— thePhoenix.HTML.Formthe field belongs to.:field— the form field as an atom.:value— explicit ISO date string; otherwise pulled from@form[@field].:locale— display locale. Defaults toLocalize.get_locale/0.:min,:max— ISO date strings orDatestructs.:placeholder— placeholder text for the text input.:display_format— one of:short,:medium(default),:long,:full. Controls the locale-formatted display shape; the wire value is always ISO.:js— set tofalseto skip thephx-hookattribute.:class,:input_class,:button_class,:overlay_class— customisation hooks.
Examples
<.date_input form={@form} field={:dob} />
<.date_input
form={@form}
field={:start_date}
min={~D[2026-01-01]}
max={~D[2026-12-31]}
display_format={:long}
/>Attributes
form(Phoenix.HTML.Form) (required)field(:atom) (required)value(:any) - Defaults tonil.locale(:any) - Defaults tonil.min(:any) - Defaults tonil.max(:any) - Defaults tonil.placeholder(:string) - Defaults tonil.display_format(:atom) - Defaults to:medium. Must be one of:short,:medium,:long, or:full.calendar(:atom) - Defaults to:gregorian.variant(:atom) - Defaults to:auto. Must be one of:auto,:dropdown, or:sheet.js(:boolean) - Defaults totrue.class(:string) - Defaults tonil.input_class(:string) - Defaults tonil.button_class(:string) - Defaults tonil.overlay_class(:string) - Defaults tonil.- Global attributes are accepted. Supports all globals plus:
["disabled", "readonly", "required", "autofocus"].
Locale-aware date-range input.
Renders two paired text inputs (from / to) inside a single
grouped wrapper. Each field is independently editable; the
pair submits as params[field] = %{"from" => "YYYY-MM-DD", "to" => "YYYY-MM-DD"}.
Server-side, parse with
Calendrical.Date.parse_range/2 passing the {from, to}
tuple from params[field].
Attributes
:form— thePhoenix.HTML.Formthe field belongs to.:field— the form field as an atom; sub-fields submit underparams[field][from]andparams[field][to].:locale,:min,:max,:display_format,:variant,:js— passed through to both inputs.:class,:input_class,:button_class,:overlay_class— customisation hooks.
Examples
<.date_range_input form={@form} field={:stay} />
<.date_range_input
form={@form}
field={:trip}
min={~D[2026-01-01]}
max={~D[2026-12-31]}
/>Attributes
form(Phoenix.HTML.Form) (required)field(:atom) (required)locale(:any) - Defaults tonil.min(:any) - Defaults tonil.max(:any) - Defaults tonil.placeholder_from(:string) - Defaults tonil.placeholder_to(:string) - Defaults tonil.display_format(:atom) - Defaults to:medium. Must be one of:short,:medium,:long, or:full.calendar(:atom) - Defaults to:gregorian.variant(:atom) - Defaults to:auto. Must be one of:auto,:dropdown, or:sheet.js(:boolean) - Defaults totrue.class(:string) - Defaults tonil.input_class(:string) - Defaults tonil.button_class(:string) - Defaults tonil.overlay_class(:string) - Defaults tonil.
Locale-aware date-range input with a unified popup
calendar (click start, then click end inside the same
grid). Pairs with RangePicker JS hook.
Renders two text inputs (visible "from" and "to") plus a single shared trigger and overlay. The user clicks the trigger to open the popup, clicks once for the start, hovers to preview, clicks again for the end. Both text inputs and both hidden ISO inputs populate.
Submits as params[field] = %{"from" => "YYYY-MM-DD", "to" => "YYYY-MM-DD"}. Server-side, parse with
Calendrical.Date.parse_range/2 passing the
{from, to} tuple.
Attributes
Same shape as date_range_input/1: :form, :field,
:locale, :min, :max, :display_format,
:calendar, :variant, :js, :class, etc.
Examples
<.date_range_picker form={@form} field={:stay} />Attributes
form(Phoenix.HTML.Form) (required)field(:atom) (required)locale(:any) - Defaults tonil.min(:any) - Defaults tonil.max(:any) - Defaults tonil.placeholder_from(:string) - Defaults tonil.placeholder_to(:string) - Defaults tonil.display_format(:atom) - Defaults to:medium. Must be one of:short,:medium,:long, or:full.calendar(:atom) - Defaults to:gregorian.variant(:atom) - Defaults to:auto. Must be one of:auto,:dropdown, or:sheet.js(:boolean) - Defaults totrue.class(:string) - Defaults tonil.input_class(:string) - Defaults tonil.button_class(:string) - Defaults tonil.overlay_class(:string) - Defaults tonil.