PhoenixLiveCalendar.CalendarComponent (PhoenixLiveCalendar v0.5.0)

Copy Markdown View Source

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_today are ready-made Phoenix.LiveView.JS commands pre-targeted at the component, and view_options is an ordered list of %{view, label, active?, command} descriptors (localized labels via the component's translations), 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). myself is the component's CID for custom pushes. Replacement is total: the :toolbar_start/:toolbar_end/:info slots render inside the STOCK toolbar only, so fold that content into your own chrome. The container's rounded-lg doesn't clip children — give opaque chrome rounded-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.