Skip to main content

README.md

# AddToCalendar

[![Hex.pm](https://img.shields.io/hexpm/v/add_to_calendar.svg)](https://hex.pm/packages/add_to_calendar)
[![Hex downloads](https://img.shields.io/hexpm/dt/add_to_calendar.svg)](https://hex.pm/packages/add_to_calendar)
[![Hexdocs](https://img.shields.io/badge/hexdocs-docs-8e7ce6)](https://hexdocs.pm/add_to_calendar)
[![Pipeline status](https://gitlab.com/roelandvanbatenburg/add_to_calendar/badges/main/pipeline.svg)](https://gitlab.com/roelandvanbatenburg/add_to_calendar/-/pipelines)
[![Coverage](https://gitlab.com/roelandvanbatenburg/add_to_calendar/badges/main/coverage.svg)](https://gitlab.com/roelandvanbatenburg/add_to_calendar/-/pipelines)
[![License](https://img.shields.io/hexpm/l/add_to_calendar.svg)](LICENSE)

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`:

```elixir
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](https://gitlab.com/roelandvanbatenburg/add_to_calendar/-/raw/main/docs/images/calendar_button_demo.gif)

```heex
<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:

- `"google"` — Google Calendar (opens in new tab)
- `"outlook"` — Outlook.com (opens in new tab)
- `"apple"` — iCal download labelled "Apple Calendar"
- `"ical"` — iCal download labelled "iCal / Other"

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

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

#### Styling

- `class` — applied to the outer `<details>` wrapper.
- `button_class` — applied to the `<summary>` trigger, replacing the default
  (`rounded px-2.5 py-1 text-sm font-medium ring-1 ring-inset ring-current
  hover:bg-black/5`) rather than merging with it.
- `icon` — set to `false` to hide the calendar glyph on the trigger.

```heex
<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

```elixir
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](https://mise.jdx.dev) 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](https://hexdocs.pm/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](LICENSE)