# `PhiaUi.Components.DatePicker`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/components/calendar/date_picker.ex#L1)

Date picker component that composes `Calendar` and a popover-style dropdown.

The date picker is fully server-rendered. The parent LiveView owns all state
(`open`, `value`, `current_month`) and handles the events emitted by the
trigger button and the embedded calendar. There is no client-side JS hook.

## Sub-components

- `date_picker/1` — standalone date picker with trigger button + calendar dropdown
- `form_date_picker/1` — `Phoenix.HTML.FormField`-integrated variant with hidden
  input and changeset error display

## When to use

Use `date_picker/1` for any date-selection field in a form or settings panel —
booking dates, birth dates, expiry dates, due dates, etc.

Use `form_date_picker/1` when the field is part of a Phoenix form backed by an
Ecto changeset, so validation errors are automatically displayed.

For selecting a date range (check-in / check-out, report period), use
`date_range_picker/1` instead.

## Standalone example

    defmodule MyAppWeb.EventLive do
      use Phoenix.LiveView

      def mount(_params, _session, socket) do
        {:ok, assign(socket,
          picker_open: false,
          selected_date: nil,
          current_month: Date.beginning_of_month(Date.utc_today())
        )}
      end

      def handle_event("toggle-picker", _params, socket) do
        {:noreply, update(socket, :picker_open, &(!&1))}
      end

      def handle_event("date-selected", %{"date" => iso}, socket) do
        date = Date.from_iso8601!(iso)
        {:noreply, assign(socket, selected_date: date, picker_open: false)}
      end

      def handle_event("calendar-prev-month", %{"month" => iso}, socket) do
        {:noreply, assign(socket, current_month: Date.from_iso8601!(iso))}
      end

      def handle_event("calendar-next-month", %{"month" => iso}, socket) do
        {:noreply, assign(socket, current_month: Date.from_iso8601!(iso))}
      end
    end

    <%!-- Template --%>
    <.date_picker
      id="event-date"
      open={@picker_open}
      value={@selected_date}
      current_month={@current_month}
      on_toggle="toggle-picker"
      on_change="date-selected"
      min={Date.utc_today()}
      placeholder="Select event date"
    />

## Form-integrated example

    <.form for={@form} phx-submit="save_event">
      <.form_date_picker
        id="start-date-picker"
        field={@form[:start_date]}
        open={@picker_open}
        value={@selected_date}
        current_month={@current_month}
        on_toggle="toggle-picker"
        on_change="date-selected"
        placeholder="Pick a start date"
      />
      <.button type="submit">Save</.button>
    </.form>

## Date format

The `:format` attribute uses `Calendar.strftime/2` directives:

| Format string | Output example   |
|---------------|-----------------|
| `"%d/%m/%Y"`  | `"25/12/2026"`  |
| `"%B %d, %Y"` | `"December 25, 2026"` |
| `"%Y-%m-%d"`  | `"2026-12-25"`  |

# `date_picker`

Renders a date picker with a trigger button and a calendar dropdown.

The parent LiveView must handle four events:

- `on_toggle` — toggle the popover open/closed
- `on_change` — a day was clicked (close the picker and update `value`)
- `"calendar-prev-month"` — navigate to the previous month
- `"calendar-next-month"` — navigate to the next month

The calendar dropdown is conditionally rendered with `:if={@open}`, so it
is completely absent from the DOM when closed (no CSS visibility tricks).

## Attributes

* `id` (`:string`) (required) - Unique date picker ID — also used as the calendar's `id` prefix.
* `value` (`:any`) - Selected date (`Date.t()`) or `nil` when no date has been chosen. Defaults to `nil`.
* `current_month` (`:any`) - Currently displayed month (`Date.t()`). When `nil`, defaults to the month
  of `:value`, or the current month if `:value` is also nil.
  Update this in response to `calendar-prev-month` / `calendar-next-month` events.

  Defaults to `nil`.
* `open` (`:boolean`) - Whether the calendar dropdown is currently visible. Controlled by the LiveView. Defaults to `false`.
* `placeholder` (`:string`) - Trigger button text displayed when no date is selected. Defaults to `"Pick a date"`.
* `format` (`:string`) - `Calendar.strftime/2` format string used to display the selected date in the trigger.
  Defaults to `"%d/%m/%Y"` (e.g. `"25/12/2026"`).

  Defaults to `"%d/%m/%Y"`.
* `on_toggle` (`:string`) - `phx-click` event name for the trigger button to toggle the dropdown open/closed. Defaults to `"date-picker-toggle"`.
* `on_change` (`:string`) - `phx-click` event fired when a day is clicked. Receives `%{"date" => "YYYY-MM-DD"}`. Defaults to `"calendar-change"`.
* `min` (`:any`) - Minimum selectable date (`Date.t()`). Passed through to the embedded `calendar/1`. Defaults to `nil`.
* `max` (`:any`) - Maximum selectable date (`Date.t()`). Passed through to the embedded `calendar/1`. Defaults to `nil`.
* `disabled_dates` (`:list`) - List of `Date.t()` values that cannot be selected. Passed through to `calendar/1`. Defaults to `[]`.
* `class` (`:string`) - Additional CSS classes merged onto the root element. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the root div element.

# `form_date_picker`

Renders a date picker integrated with `Phoenix.HTML.FormField`.

Renders a `<input type="hidden">` bound to `field.name` with the ISO 8601
date value. This hidden input is what gets submitted with the form so Phoenix
changesets receive a string they can cast with `cast/3`.

Changeset validation errors from `field.errors` are rendered as destructive
text below the picker.

## Changeset integration

Cast the hidden input value in your changeset:

    def changeset(event, attrs) do
      event
      |> cast(attrs, [:start_date])
      |> validate_required([:start_date])
    end

The hidden input sends an ISO 8601 string (`"2026-03-15"`), which Ecto's
`Date` type will automatically parse during `cast/3`.

## Attributes

* `field` (`Phoenix.HTML.FormField`) (required) - `Phoenix.HTML.FormField` struct from `@form[:field_name]`.
  Provides the `id`, `name`, and `errors` for form integration.

* `id` (`:string`) (required) - Unique date picker ID (separate from `field.id` which is used for the hidden input).
* `value` (`:any`) - Selected date (`Date.t()`) or `nil`. Defaults to `nil`.
* `current_month` (`:any`) - Currently displayed month (`Date.t()`). Defaults to `nil`.
* `open` (`:boolean`) - Whether the popover is open. Defaults to `false`.
* `placeholder` (`:string`) - Placeholder text. Defaults to `"Pick a date"`.
* `format` (`:string`) - `Calendar.strftime/2` format string for displaying the selected date. Defaults to `"%d/%m/%Y"`.
* `on_toggle` (`:string`) - `phx-click` event name for the trigger button. Defaults to `"date-picker-toggle"`.
* `on_change` (`:string`) - `phx-click` event name for day clicks in the embedded calendar. Defaults to `"calendar-change"`.
* `class` (`:string`) - Additional CSS classes for the wrapper div. Defaults to `nil`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
