AddToCalendar

Hex.pmHex downloadsHexdocsPipeline statusCoverageLicense

Server-side calendar links and ICS generation for Phoenix LiveView apps.

Generates Google Calendar / Outlook.com URLs and downloadable .ics files from plain Elixir Date / Time structs — no JavaScript dependency, no timezone database required.

Installation

Add add_to_calendar to your list of dependencies in mix.exs:

def deps do
[
{:add_to_calendar, "~> 0.1.0"}
]
end

phoenix_live_view is an optional dependency — only required if you use AddToCalendar.Component.

Usage

Phoenix component

AddToCalendar.Component.calendar_button/1 renders a ready-made dropdown using a native <details>/<summary> element — no JavaScript required.

Add to Calendar button opening a dropdown with Google, Apple, iCal, and Outlook.com options

<AddToCalendar.Component.calendar_button
name={@event.title}
start_date={@event.starts_on}
start_time={@event.start_time}
end_date={@event.ends_on}
end_time={@event.end_time}
timezone={@event.timezone}
location={@full_address}
description={@event.description}
/>

The :providers attr controls which options appear, in order:

If using Tailwind CSS, add this package to your content paths so its class names are included in the build:

content: ["../deps/add_to_calendar/lib/**/*.ex"]

Styling

<AddToCalendar.Component.calendar_button
...
class="inline-block"
button_class="rounded-full bg-indigo-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-indigo-500"
/>

The dropdown panel and its links aren't exposed as attrs — their classes (bg-white, border-gray-200, text-gray-700, etc.) are fixed. If you need to restyle the panel itself, wrap the component, copy component.ex into your app or create a MR fixing this.

Without Phoenix component

event = %AddToCalendar.Event{
name: "Pickleball League",
start_date: ~D[2026-07-15],
start_time: ~T[09:00:00],
end_date: ~D[2026-07-15],
end_time: ~T[11:00:00],
timezone: "Pacific/Auckland",
location: "123 Main St, Auckland",
description: "Weekly round-robin"
}
AddToCalendar.google_url(event)
# => "https://calendar.google.com/calendar/render?..."
AddToCalendar.outlook_url(event)
# => "https://outlook.live.com/calendar/0/action/compose?..."
AddToCalendar.ics_content(event)
# => "BEGIN:VCALENDAR\r\n..."
AddToCalendar.ics_data_uri(event)
# => "data:text/calendar;charset=utf-8;base64,..."

Development

Toolchain versions are pinned in .tool-versions (compatible with mise or asdf).

mix deps.get
mix check

A Dockerfile is provided for a reproducible environment matching .tool-versions:

docker build -t add_to_calendar .
docker run --rm add_to_calendar

Previewing AddToCalendar.Component

This is a standalone library, so there's no host app to render calendar_button/1 in a browser while iterating on its styling. A dev-only Phoenix Storybook app under dev/ fills that gap, with stories under dev/storybook/.

mix phx.server

Then visit http://localhost:4000. Elixir changes (e.g. to component.ex) and Tailwind CSS changes both live-reload the page. This tooling only exists for MIX_ENV=dev (see elixirc_paths and the application/0 mod in mix.exs) and is excluded from the published package.

License

MIT