HEEx components that render an EventCalendar.
calendar/1- for Phoenix LiveView, driven by theLiveCalendarhookstatic_calendar/1- for regular controllers, initialized with vanilla JavaScript
Both components serialize events and options to JSON data-* attributes that the
bundled JavaScript passes to EventCalendar. Any EventCalendar option can be given in
options (see the EventCalendar docs).
Interaction callbacks (LiveView)
calendar/1 forwards EventCalendar interactions to LiveView. Each callback attribute accepts:
a string - the name of the event pushed to the server with the callback payload
a
Phoenix.LiveView.JSstruct - commands executed on the client. EveryJS.push/2in it receives the callback payload merged into its:valuefalse- disables the default server event of that callbackalias Phoenix.LiveView.JS
<.calendar id="calendar" events={@events} options={%{view: "dayGridMonth", editable: true, selectable: true}} on_event_click={JS.push("select_event") |> JS.show(to: "#event-modal")} on_event_drop="event_dropped" on_select="range_selected" />
on_event_click, on_date_click and on_month_change push "event_clicked",
"date_clicked" and "month_changed" by default, unless they are given a string,
false, or JS commands that already include a JS.push/2. on_event_drop,
on_event_resize and on_select push nothing unless configured.
The handlers of on_event_drop and on_event_resize can reply %{revert: true} to
move the event back to where it was:
def handle_event("event_dropped", %{"id" => id, "event" => event}, socket) do
case Events.reschedule(id, event["start"], event["end"]) do
{:ok, _} -> {:noreply, socket}
{:error, _} -> {:reply, %{revert: true}, socket}
end
end
Summary
Functions
Renders a calendar for LiveView, managed by the LiveCalendar hook.
Renders a calendar for regular Phoenix controllers (no LiveView required).
Functions
Renders a calendar for LiveView, managed by the LiveCalendar hook.
The container uses phx-update="ignore", so LiveView keeps the calendar DOM intact
while events and options changes are still applied by the hook. Only options whose
value changed are re-applied, so re-renders don't reset the date or view the user
navigated to.
Payloads
Dates are sent twice: as instants ("start", "end", "date", e.g.
"2026-10-19T13:00:00.000Z") and as wall-clock strings in the calendar's timeZone
("startStr", "endStr", "dateStr", e.g. "2026-10-19T10:00:00").
on_event_click-%{"id", "event", "view"}on_date_click-%{"date", "dateStr", "allDay", "resource", "view"}on_month_change-%{"month", "year", "start", "end", "startStr", "endStr", "view"}on_event_drop-%{"id", "event", "oldEvent", "delta", "oldResource", "newResource", "view"}on_event_resize-%{"id", "event", "oldEvent", "startDelta", "endDelta", "view"}on_select-%{"start", "end", "startStr", "endStr", "allDay", "resource", "view"}
"event" is a map with "id", "title", "start", "end", "startStr", "endStr",
"allDay", "resourceIds", "display", "backgroundColor", "textColor" and
"extendedProps". "view" holds "type", "title" and the visible range.
Examples
<.calendar id="calendar" events={@events} options={%{view: "dayGridMonth"}} />Attributes
id(:string) (required)events(:list) - EventCalendar events (maps encodable with Jason). Defaults to[].options(:map) - EventCalendar options. Defaults to%{}.on_event_click(:any) - Server event name (string),%Phoenix.LiveView.JS{}commands orfalse. Defaults tonil.on_date_click(:any) - Server event name (string),%Phoenix.LiveView.JS{}commands orfalse. Defaults tonil.on_month_change(:any) - Server event name (string),%Phoenix.LiveView.JS{}commands orfalse. Defaults tonil.on_event_drop(:any) - Server event name (string),%Phoenix.LiveView.JS{}commands orfalse. Defaults tonil.on_event_resize(:any) - Server event name (string),%Phoenix.LiveView.JS{}commands orfalse. Defaults tonil.on_select(:any) - Server event name (string),%Phoenix.LiveView.JS{}commands orfalse. Defaults tonil.- Global attributes are accepted. Global attributes (class, style, data-, aria-, ...).
Renders a calendar for regular Phoenix controllers (no LiveView required).
The container gets the static-calendar class and is initialized by the
calendar_component/static module (automatically on page load, or with
initStaticCalendars()).
Callbacks
Callback options (eventClick, dateClick, datesSet, eventDrop, eventResize,
select, eventDidMount, ... and customButtons.*.click) can be given as strings:
- a global function reference (recommended):
"MyApp.Calendar.onEventClick" - a short function body that receives
info(max. 200 characters, keywords likefunction,evalorsetTimeoutare rejected):"console.log(info.event.title)"
Example
<.static_calendar
id="my-calendar"
events={@events}
options={%{
view: "dayGridMonth",
eventClick: "MyApp.Calendar.onEventClick",
dateClick: "MyApp.Calendar.onDateClick",
datesSet: "MyApp.Calendar.onMonthChange"
}}
/>import {initStaticCalendars} from "calendar_component/static"
window.MyApp = {
Calendar: {
onEventClick(info) { console.log("Event clicked:", info.event.title) },
onDateClick(info) { console.log("Date clicked:", info.dateStr) },
onMonthChange(info) { console.log("Range:", info.startStr, info.endStr) }
}
}
initStaticCalendars()Attributes
id(:string) (required)events(:list) - EventCalendar events (maps encodable with Jason). Defaults to[].options(:map) - EventCalendar options, callbacks given as strings. Defaults to%{}.class(:any) - Extra classes, added tostatic-calendar. Defaults tonil.- Global attributes are accepted. Global attributes (style, data-, aria-, ...).