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

A full-month calendar grid where multiple individual (non-contiguous) dates
can be toggled on/off.

Selected dates are rendered as individual filled rounded rectangles using
`bg-primary/20 text-primary font-semibold`. This is distinct from
`RangeCalendar`, which selects a contiguous band of dates.

The grid is SUN-first (Sun Mon Tue Wed Thu Fri Sat). Adjacent-month days are
rendered faded (`opacity-40`) to fill the first and last rows.

Month and year navigation is provided through navigation buttons (`on_prev`,
`on_next`) and/or `<select>` dropdowns (`on_month_change`, `on_year_change`).
State (current month/year, selected dates) lives entirely in the parent
LiveView.

## Example

    <.multi_select_calendar
      year={@year}
      month={@month}
      selected_dates={@selected_dates}
      on_select="toggle_date"
      on_prev="prev_month"
      on_next="next_month"
      on_month_change="month_changed"
      on_year_change="year_changed"
    />

## LiveView event handlers

    def handle_event("toggle_date", %{"date" => iso}, socket) do
      date = Date.from_iso8601!(iso)
      selected =
        if date in socket.assigns.selected_dates do
          List.delete(socket.assigns.selected_dates, date)
        else
          [date | socket.assigns.selected_dates]
        end
      {:noreply, assign(socket, selected_dates: selected)}
    end

    def handle_event("prev_month", _params, socket) do
      {y, m} = prev_ym(socket.assigns.year, socket.assigns.month)
      {:noreply, assign(socket, year: y, month: m)}
    end

    def handle_event("next_month", _params, socket) do
      {y, m} = next_ym(socket.assigns.year, socket.assigns.month)
      {:noreply, assign(socket, year: y, month: m)}
    end

    def handle_event("month_changed", %{"month" => m}, socket) do
      {:noreply, assign(socket, month: String.to_integer(m))}
    end

    def handle_event("year_changed", %{"year" => y}, socket) do
      {:noreply, assign(socket, year: String.to_integer(y))}
    end

## Zero JavaScript

This component is entirely server-rendered. No JS hook is required.

# `multi_select_calendar`

Renders a single-month calendar grid supporting multiple individual date
selections.

All geometry (leading/trailing days, per-cell selection state) is computed
server-side before the template renders.

## Attributes

* `year` (`:integer`) (required) - 4-digit year of the displayed month.
* `month` (`:integer`) (required) - Month number (1–12).
* `selected_dates` (`:list`) - List of `Date.t()` values that are currently selected. Defaults to `[]`.
* `on_select` (`:string`) - `phx-click` event name fired when any current-month day is clicked.
  The LiveView receives `%{"date" => "YYYY-MM-DD"}`. Clicking a selected date
  again is intended to deselect it — the toggle logic lives in the parent.

  Defaults to `nil`.
* `on_prev` (`:string`) - `phx-click` event name for the previous-month navigation button. Defaults to `nil`.
* `on_next` (`:string`) - `phx-click` event name for the next-month navigation button. Defaults to `nil`.
* `on_month_change` (`:string`) - `phx-change` event name for the month `<select>` dropdown. Defaults to `nil`.
* `on_year_change` (`:string`) - `phx-change` event name for the year `<select>` dropdown. Defaults to `nil`.
* `min_year` (`:integer`) - Earliest year shown in the year `<select>` dropdown. Defaults to `2000`.
* `max_year` (`:integer`) - Latest year shown in the year `<select>` dropdown. Defaults to `2040`.
* `class` (`:string`) - Additional CSS classes merged onto the root element. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the root `<div>`.

---

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