DevactionUI.DatePicker (devaction_ui v0.2.3)

Copy Markdown View Source

A month calendar that picks one day or a range, and the small chip that says how near a deadline is.

date_picker/1 is drawn by a hook, so the months turn without the server. The server gives it only what it alone knows: the day that is today in the workspace's time zone (today), the shortcuts (Today, Friday, +7 days, End of the milestone, each with its ISO date) and the texts. Month and weekday names come from the browser's Intl in the locale given. The choice goes into hidden inputs (name for one day, name_from and name_to for a range), as ISO dates, and the hook fires input so phx-change hears it.

Keys: ← → move a day, ↑ ↓ a week, PageUp and PageDown a month, Home and End the week, Enter or Space picks. Days before min are dimmed and cannot be picked, and the keyboard lands on min when today is before it. The days are buttons in a labelled group, not a grid.

The element is phx-update="ignore" (the browser owns the month on show), so a new value from the server is not drawn: give the picker a new id to reset it, or send it the dates without a new id:

JS.dispatch("devaction:date-picker-set", to: "#due-picker", detail: %{from: "2026-10-16", to: nil})

The month title is capitalised unless capitalize is false; the arrows are the prev_icon and next_icon slots (a typographic arrow when empty). Leave name out when something else owns the form value, as the fields below do: the hidden inputs then have no name and are not sent.

date_input/1 and date_range/1 are the fields of a form: a text field with a mask in the order of the dates of the language (order :dmy, :mdy or :ymd, and the separator) and a button that opens a calendar in a DevactionUI.Popover. What is sent is a hidden input with the ISO date (name for a day, name_from and name_to for a range); the visible text has no name. Typing fills the calendar and picking in the calendar fills the text, and phx-change hears one input per change. The label, the description and the error are attrs (error is the message, shown under the field and tied to it with aria-describedby), and relative is the text on the right of the field (in 3 days), which the server computes, so it follows the value when the form is sent back. A day that does not exist, or one before min, is marked aria-invalid as it is typed. In a range the end cannot be before the start.

due_chip/1 compares a date with today and draws it late (red), due today (amber) or later (neutral); with recurring it is a grey chip for a repeating deadline, with its own icon (a ↻ when the slot is empty).

Summary

Functions

An ISO date (or a Date) as the text of a date field: 16/10/2026 for :dmy and "/", nothing for nil.

:late, :today or :later.

Functions

date_input(assigns)

Attributes

  • id (:string) (required)
  • name (:string) (required) - the name of the hidden input that carries the ISO date.
  • label (:string) (required) - the visible label of the field.
  • value (:any) - an ISO date, a Date or nil. Defaults to nil.
  • today (:string) (required) - today's ISO date in the workspace's time zone.
  • min (:string) - the first ISO date that can be picked or typed. Defaults to nil.
  • locale (:string) - the language of the month and day names in the calendar. Defaults to "en".
  • week_start (:integer) - 0 for Sunday, 1 for Monday. Defaults to 0.
  • order (:atom) - the order of day, month and year in the text. Defaults to :dmy. Must be one of :dmy, :mdy, or :ymd.
  • separator (:string) - the character between the parts of the text. Defaults to "/".
  • placeholder (:string) - e.g. dd/mm/yyyy, written in the language of the person. Defaults to nil.
  • description (:string) - help text under the field. Defaults to nil.
  • error (:string) - the message under the field; marks it invalid. Defaults to nil.
  • relative (:string) - text on the right of the field, e.g. in 3 days. Defaults to nil.
  • disabled (:boolean) - Defaults to false.
  • required (:boolean) - Defaults to false.
  • calendar_label (:string) (required) - names the button and the panel of the calendar.
  • previous_label (:string) (required)
  • next_label (:string) (required)
  • class (:any) - Defaults to nil.
  • Global attributes are accepted. goes to the box around the label and the field.

Slots

  • icon - the calendar icon at the start of the field; it is the button that opens the calendar.
  • prev_icon - the icon of the previous month button.
  • next_icon - the icon of the next month button.
  • shortcut - Accepts attributes:
    • date (:string) (required) - an ISO date.

date_picker(assigns)

Attributes

  • id (:string) (required)
  • name (:string) - the name of the hidden inputs; without it they are not sent. Defaults to nil.
  • mode (:atom) - Defaults to :single. Must be one of :single, or :range.
  • value (:any) - an ISO date, or {from, to} for a range, or nil. Defaults to nil.
  • today (:string) (required) - today's ISO date in the workspace's time zone.
  • min (:string) - the first ISO date that can be picked. Defaults to nil.
  • locale (:string) - Defaults to "en".
  • week_start (:integer) - 0 for Sunday, 1 for Monday. Defaults to 0.
  • previous_label (:string) (required)
  • next_label (:string) (required)
  • capitalize (:boolean) - upper-case the first letter of the month title. Defaults to true.
  • inside_label (:string) - added to the name of the days between the ends of a range, e.g. in the range. Defaults to nil.
  • shadow (:boolean) - the panel's shadow, for use inside a popover. Defaults to false.
  • class (:any) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • prev_icon - the icon of the previous month button.
  • next_icon - the icon of the next month button.
  • shortcut - Accepts attributes:
    • date (:string) (required) - an ISO date.

date_range(assigns)

Attributes

  • id (:string) (required)
  • name (:string) (required) - name_from and name_to are the hidden inputs.
  • label (:string) (required) - the visible label of the pair.
  • value (:any) - {from, to} of ISO dates or Dates, or nil. Defaults to nil.
  • today (:string) (required) - today's ISO date in the workspace's time zone.
  • min (:string) - Defaults to nil.
  • locale (:string) - Defaults to "en".
  • week_start (:integer) - Defaults to 0.
  • order (:atom) - Defaults to :dmy. Must be one of :dmy, :mdy, or :ymd.
  • separator (:string) - Defaults to "/".
  • placeholder (:string) - the placeholder of both fields. Defaults to nil.
  • from_label (:string) (required) - names the start field for assistive technology.
  • to_label (:string) (required) - names the end field for assistive technology.
  • inside_label (:string) - added to the days between the ends, in the calendar. Defaults to nil.
  • description (:string) - Defaults to nil.
  • error (:string) - Defaults to nil.
  • disabled (:boolean) - Defaults to false.
  • required (:boolean) - Defaults to false.
  • calendar_label (:string) (required)
  • previous_label (:string) (required)
  • next_label (:string) (required)
  • class (:any) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • icon - the calendar icon at the start of the first field; it opens the calendar.
  • arrow - between the two fields; a → when empty.
  • prev_icon
  • next_icon
  • shortcut - Accepts attributes:
    • date (:string) (required) - an ISO date.

due_chip(assigns)

Attributes

  • date (:any) - a Date; not needed for a recurring chip. Defaults to nil.
  • today (:any) - a Date: today in the workspace's time zone; not needed for a recurring chip. Defaults to nil.
  • text (:string) (required) - what the chip says, already in the person's language.
  • recurring (:boolean) - a grey chip for a repeating deadline. Defaults to false.
  • class (:any) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • icon - the icon of a recurring chip; a ↻ when empty.

format_date(date, order, separator)

@spec format_date(Date.t() | String.t() | nil, :dmy | :mdy | :ymd, String.t()) ::
  String.t()

An ISO date (or a Date) as the text of a date field: 16/10/2026 for :dmy and "/", nothing for nil.

iex> DevactionUI.DatePicker.format_date("2026-10-16", :mdy, "/")
"10/16/2026"

state(date, today)

@spec state(Date.t(), Date.t()) :: :late | :today | :later

:late, :today or :later.