Skip to main content

Menu

Choose a theme and configure high-contrast mode. Preferences are saved in your browser only.

User Preferences

Theme

Pick a palette or follow your system preference.

High Contrast

Sharper text and borders. System follows your OS setting.

Declarative triggers

Turn any element into a calendar trigger with data-twistcal attributes. Auto-initializes on DOMContentLoaded, or bind manually for dynamic content.

Use your own buttons, links, or divs. Add data-twistcal to any element and it becomes a calendar trigger — no JS needed. Auto-initializes on DOMContentLoaded.

<script defer src="https://cdn.jsdelivr.net/npm/@freshjuice/twistcal/dist/twistcal.min.js"></script>

<!-- Google Calendar -->
<button data-twistcal
  data-twistcal-action="google"
  data-twistcal-title="Team Sync"
  data-twistcal-start="2026-01-15T10:00:00"
  data-twistcal-end="2026-01-15T11:00:00"
  data-twistcal-location="Room A">
  Add to Google
</button>

<!-- Outlook -->
<a href="#" data-twistcal
  data-twistcal-action="outlook"
  data-twistcal-title="Team Sync"
  data-twistcal-start="2026-01-15T10:00:00"
  data-twistcal-end="2026-01-15T11:00:00">
  Add to Outlook
</a>

<!-- Download .ics -->
<button data-twistcal
  data-twistcal-action="ics"
  data-twistcal-title="Team Sync"
  data-twistcal-start="2026-01-15T10:00:00"
  data-twistcal-end="2026-01-15T11:00:00">
  Download .ics
</button>

Trigger attributes

Attribute Required Description
data-twistcal yes Marks the element as a trigger
data-twistcal-action yes google | outlook | yahoo | ics
data-twistcal-title yes Event title
data-twistcal-start yes Start datetime
data-twistcal-end yes End datetime
data-twistcal-description no Event description
data-twistcal-location no Event location
data-twistcal-url no Event URL (.ics only)
data-twistcal-timezone no IANA timezone

Manual binding

Auto-init a container

If you add triggers dynamically (e.g. after an AJAX load), call autoInit on the new container:

import { autoInit } from '@freshjuice/twistcal';

// After injecting HTML:
autoInit(document.getElementById('new-content'));

Bind a single element

Or bind a single element with an explicit event object (skips attribute parsing):

import { bindTrigger } from '@freshjuice/twistcal';

const event = {
  title: 'Team Sync',
  start: '2026-01-15T10:00:00',
  end: '2026-01-15T11:00:00'
};
bindTrigger(document.getElementById('my-btn'), 'google', event);

twistcal:add event

Each trigger click fires a twistcal:add CustomEvent on document with { action, event } detail:

document.addEventListener('twistcal:add', (e) => {
  console.log('Added to:', e.detail.action, e.detail.event);
});

Next

  • APIautoInit, bindTrigger, and all exports
  • Web component — the <twist-cal> element