1) Dependency

Add the library to your dependencies in mix.exs and fetch it:

def deps do
  [
    {:calendar_component, "~> 0.3.0"}
  ]
end
mix deps.get

The JavaScript and CSS are prebuilt in priv/static/assets, so there is nothing to install with npm.

2) JavaScript

Phoenix's default esbuild configuration sets NODE_PATH to deps/, so the package can be imported by name from assets/js/app.js.

LiveView

import {Socket} from "phoenix"
import {LiveSocket} from "phoenix_live_view"
import CalendarHooks from "calendar_component"

const csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
const liveSocket = new LiveSocket("/live", Socket, {
  params: {_csrf_token: csrfToken},
  hooks: {...CalendarHooks}
})
liveSocket.connect()

If you already have hooks (including colocated hooks), merge them:

import {hooks as colocatedHooks} from "phoenix-colocated/my_app"

const liveSocket = new LiveSocket("/live", Socket, {
  params: {_csrf_token: csrfToken},
  hooks: {...colocatedHooks, ...CalendarHooks}
})

Controllers (no LiveView)

import {initStaticCalendars} from "calendar_component"

// Calendars are initialized automatically on page load; call it again after inserting
// calendars dynamically.
initStaticCalendars()

Apps that don't use LiveView at all can import the smaller calendar_component/static bundle instead. Don't import both entry points: each one includes its own copy of EventCalendar.

3) CSS

Import the EventCalendar stylesheet in assets/css/app.css:

@import "../../deps/calendar_component/priv/static/assets/main.css";

esbuild also emits the stylesheet next to app.js when the package is imported, but the default Phoenix layout only links the Tailwind output, so the @import above is the reliable way to load it.

4) Verification

defmodule MyAppWeb.CalendarLive do
  use MyAppWeb, :live_view

  import LiveCalendar.Components

  def mount(_params, _session, socket) do
    today = Date.utc_today()

    events = [
      %{id: 1, title: "Sample event", start: NaiveDateTime.new!(today, ~T[10:00:00]), end: NaiveDateTime.new!(today, ~T[11:00:00])}
    ]

    {:ok, assign(socket, events: events)}
  end

  def render(assigns) do
    ~H"""
    <.calendar id="my-calendar" events={@events} options={%{view: "dayGridMonth"}} />
    """
  end

  def handle_event(_event, _params, socket), do: {:noreply, socket}
end

For a controller:

defmodule MyAppWeb.EventController do
  use MyAppWeb, :controller

  def index(conn, _params) do
    events = [%{id: 1, title: "Sample event", start: Date.utc_today()}]
    render(conn, :index, events: events)
  end
end
<%!-- lib/my_app_web/controllers/event_html/index.html.heex --%>
<LiveCalendar.Components.static_calendar id="my-static-calendar" events={@events} options={%{view: "dayGridMonth"}} />

5) Versions and compatibility