The main calendar LiveComponent.
Manages internal state (current date, view mode, navigation) and renders the appropriate view. Communicates with the parent via callback functions.
Usage
<.live_component
module={PhoenixLiveCalendar.CalendarComponent}
id="my-calendar"
events={@events}
on_date_select={fn date -> send(self(), {:date_selected, date}) end}
on_event_click={fn event_id -> send(self(), {:event_clicked, event_id}) end}
/>Full example with all options
<.live_component
module={PhoenixLiveCalendar.CalendarComponent}
id="booking-calendar"
events={@events}
resources={@resources}
view={:week}
views={[:day, :week, :month]}
date={@current_date}
selected_date={@selected_date}
week_start={1}
min_time={~T[08:00:00]}
max_time={~T[20:00:00]}
slot_duration={15}
time_format={:h12}
business_hours={@business_hours}
translations={%{labels: %{today: "Aujourd'hui"}}}
dir={:ltr}
on_date_select={fn date -> send(self(), {:date_selected, date}) end}
on_range_select={fn range -> send(self(), {:range_selected, range}) end}
on_event_click={fn event_id -> send(self(), {:event_clicked, event_id}) end}
on_event_drop={fn data -> send(self(), {:event_dropped, data}) end}
on_view_change={fn data -> send(self(), {:view_changed, data}) end}
/>Slots
The underlying views' customization slots are forwarded through the
component — pass them as <.live_component> children:
<.live_component module={PhoenixLiveCalendar.CalendarComponent} id="cal" events={@events}>
<:event :let={event}>
<.my_event_chip event={event} />
</:event>
</.live_component>:event— custom event rendering (month, week, day, N-day, agenda, timeline, resource):day_cell— full month day-cell replacement (receives%{date: date, events: events, markers: markers}):time_label— time gutter labels (week, day, N-day):resource_label/:resource_header— timeline / resource column labels:day_header/:no_events— agenda day headings and empty state:info— toolbar info (ⓘ) disclosure content:header— replaces the ENTIRE built-in toolbar with custom chrome. Receives%{title, view, date, today_date, today_visible, on_prev, on_next, on_today, view_options, myself}—on_prev/on_next/on_todayare ready-madePhoenix.LiveView.JScommands pre-targeted at the component, andview_optionsis an ordered list of%{view, label, active?, command}descriptors (localized labels via the component'stranslations), so a full switcher is one:for:<:header :let={h}> <button phx-click={h.on_prev}>‹</button> <span>{h.title}</span> <button phx-click={h.on_next}>›</button> <button :for={o <- h.view_options} phx-click={o.command} class={o.active? && "btn-active"} > {o.label} </button> </:header>show_header={false}suppresses the slot too (one toggle for any chrome).myselfis the component's CID for custom pushes. Replacement is total: the:toolbar_start/:toolbar_end/:infoslots render inside the STOCK toolbar only, so fold that content into your own chrome. The container'srounded-lgdoesn't clip children — give opaque chromerounded-t-[inherit](or transparent chrome like the stock header) so it doesn't paint square over the top corners.
Sizing
The calendar is an @container: the header and the month view compact
to the CONTAINER's width, not the viewport (the other views still key
their responsive tiers on the viewport for now). Container-query
containment strips intrinsic width, so the root carries w-full —
give the calendar a width-defining parent (any block/flex column
does); inside a shrink-to-fit context (inline-block, float, flex row
without a basis) a container-queried element cannot size itself by its
content.
The view area scrolls its own overflow (.cal-view-container is
overflow-auto) — EXCEPT when the month view runs with
cell_overflow: :visible, which trades the scroll container away so
custom day-cell tooltips can escape the grid. In a bounded-height
panel the month grid then overflows the panel instead of scrolling;
keep :clip (the default) where scrolling matters.