PhoenixLiveCalendar (PhoenixLiveCalendar v0.1.0)

Copy Markdown View Source

A comprehensive calendar and scheduling component library for Phoenix LiveView.

PhoenixLiveCalendar provides server-rendered calendar views (month, week, day, year, N-day, agenda, timeline, resource) with optional JavaScript hooks for drag interactions, optional PubSub for real-time sync, and optional Ecto persistence.

Quick start

# In your LiveView template
<.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 id -> send(self(), {:event_clicked, id}) end}
/>

Architecture

PhoenixLiveCalendar is built in layers, each optional:

  • Layer 0 — Pure Elixir/HEEx views (zero JS required)
  • Layer 1 — JS hooks for drag-to-select, drag-to-move, resize
  • Layer 2 — PubSub for real-time multi-user updates
  • Layer 3 — Booking constraints (availability, slots, buffers)
  • Layer 4 — Ecto persistence (optional, Oban-style migrations)

Views

ViewModuleDescription
MonthPhoenixLiveCalendar.Views.MonthGridTraditional 42-cell grid
WeekPhoenixLiveCalendar.Views.WeekGrid7 days with time axis
DayPhoenixLiveCalendar.Views.DayViewSingle day time grid
N-dayPhoenixLiveCalendar.Views.NDayViewConfigurable day count
YearPhoenixLiveCalendar.Views.YearView12 mini-months
AgendaPhoenixLiveCalendar.Views.AgendaChronological list
TimelinePhoenixLiveCalendar.Views.TimelineHorizontal time, resource rows
ResourcePhoenixLiveCalendar.Views.ResourceViewResource columns

View maturity

All eight views render server-side and are usable today. Month is the most polished — it is the primary view and the one tuned for small screens. The remaining views (week, day, N-day, year, agenda, timeline, resource) are functional but less refined; in particular the time-grid views are not yet optimised for phone widths. Expect them to gain polish in later releases.

Data structures

CSS setup

Add to your assets/css/app.css:

@source "../../deps/phoenix_live_calendar";

JS hooks setup (optional)

Add to your assets/js/app.js:

import "../../deps/phoenix_live_calendar/priv/static/assets/phoenix_live_calendar.js"

let liveSocket = new LiveSocket("/live", Socket, {
  hooks: { ...window.PhoenixLiveCalendarHooks, ...Hooks }
})

Summary

Functions

Creates a booking configuration.

Creates a day marker (date annotation).

Creates a new event struct.

Returns whether PhoenixLiveCalendar CSS integration has been wired up.

Creates a new resource struct.

Converts a list of items to events using the Eventable protocol.

Functions

availability(days_or_date, start_time, end_time, opts \\ [])

@spec availability([integer()] | Date.t(), Time.t(), Time.t(), keyword()) ::
  PhoenixLiveCalendar.Availability.t()

Creates an availability window.

Examples

# Monday through Friday, 9am to 5pm
PhoenixLiveCalendar.availability([1, 2, 3, 4, 5], ~T[09:00:00], ~T[17:00:00])

# Specific date override
PhoenixLiveCalendar.availability(~D[2026-04-15], ~T[10:00:00], ~T[14:00:00])

booking_config(opts \\ [])

@spec booking_config(keyword()) :: PhoenixLiveCalendar.BookingConfig.t()

Creates a booking configuration.

Examples

PhoenixLiveCalendar.booking_config(duration: 30, buffer_after: 5, min_notice: 60)

day_marker(id, label, start_date, opts \\ [])

@spec day_marker(term(), String.t(), Date.t(), keyword()) ::
  PhoenixLiveCalendar.DayMarker.t()

Creates a day marker (date annotation).

Examples

# Holiday
PhoenixLiveCalendar.day_marker("xmas", "Christmas Day", ~D[2026-12-25], type: :holiday, available: false)

# Multi-day notice
PhoenixLiveCalendar.day_marker("winter", "Winter Hours", ~D[2026-12-20],
  end_date: ~D[2027-01-05],
  type: :notice,
  color: "bg-info/10",
  description: "Reduced hours: 10am-3pm"
)

event(id, start, opts \\ [])

Creates a new event struct.

Examples

PhoenixLiveCalendar.event("1", ~D[2026-04-01], title: "My Event")
PhoenixLiveCalendar.event("2", ~U[2026-04-01 10:00:00Z], title: "Meeting", end: ~U[2026-04-01 11:00:00Z])

installed?()

@spec installed?() :: boolean()

Returns whether PhoenixLiveCalendar CSS integration has been wired up.

Looks for the package name in the common app.css locations and in any assets/css/*.css — so it also recognises a generated Tailwind sources file (e.g. PhoenixKit's _phoenix_kit_sources.css, which @sources the package automatically). Used at compile time to warn developers who haven't run mix phoenix_live_calendar.install and aren't wiring it some other way.

resource(id, title, opts \\ [])

@spec resource(term(), String.t(), keyword()) :: PhoenixLiveCalendar.Resource.t()

Creates a new resource struct.

Examples

PhoenixLiveCalendar.resource("room-a", "Conference Room A")
PhoenixLiveCalendar.resource("dr-smith", "Dr. Smith", type: :person, color: "bg-accent")

to_events(items)

@spec to_events([term()]) :: [PhoenixLiveCalendar.Event.t()]

Converts a list of items to events using the Eventable protocol.

Items that already are PhoenixLiveCalendar.Event structs pass through unchanged.