More Buttons Snippets
Add to Calendar Button — Google/Outlook/ICS UI
Add to Calendar Button · Buttons · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Add to Calendar Button — Multi-Provider Event Links & .ics Download

"Add to calendar" is the single most effective way to stop people forgetting an event they signed up for — but doing it right means supporting every major calendar app, because you never know whether your attendee lives in Google Calendar, Outlook, or Apple Calendar. This snippet builds a complete add-to-calendar dropdown in plain HTML, CSS, and vanilla JavaScript: pre-filled event links for Google, Outlook, Office 365, and Yahoo, plus a downloadable .ics file that works with Apple Calendar and everything else.
One event object, every provider
All the event details — title, description, location, start, and end — live in a single EVENT object. Each menu choice builds the right URL or file from it, so updating the event is a one-place change. The web providers (Google, Outlook, Office 365, Yahoo) each have their own URL format with their own parameter names and date encoding, and buildUrl() handles those differences in one function: Google and Yahoo take UTC timestamps in their dates/st/et params, while Outlook and Office 365 take ISO datetimes in startdt/enddt. Getting these formats exactly right is the fiddly part most hand-rolled implementations get wrong, and it's done here for you.
The .ics file covers Apple and everything else
Apple Calendar has no "add event" URL scheme, so the universal answer is an .ics file — the iCalendar standard that every calendar app on every platform can import. downloadIcs() assembles a minimal valid VCALENDAR/VEVENT block with the event fields and the required UTC timestamps, wraps it in a Blob, and triggers a download via a temporary object URL (revoked immediately after to avoid a memory leak). Opening that file adds the event to whatever calendar the user's device defaults to — Apple Calendar on a Mac or iPhone, or any desktop client.
Timezone handling, done correctly
Calendar URLs and .ics files want UTC timestamps in the compact YYYYMMDDTHHMMSSZ format. toUTC() parses the local ISO start/end times and converts them through Date's toISOString(), stripping the separators and milliseconds. This means you author the event in plain local time and the conversion to the calendar-required format happens automatically — the most common source of "the event landed an hour off" bugs is skipping this conversion, which this snippet does for you.
A proper accessible dropdown
The trigger carries aria-haspopup="menu" and a toggled aria-expanded, the menu is role="menu" with role="menuitem" links, and it closes on an outside click or the Escape key — the standard menu pattern. The panel animates in with opacity and transform only (never height), so it stays smooth across every framework export, and web-provider links open in a new tab with noopener for safety while the .ics choice downloads in place.
Why support so many providers
It's tempting to ship only a Google Calendar link, but that abandons every Outlook and Apple user — a large share of any audience. Offering all the major web providers plus the universal .ics file means essentially everyone can add your event in one click, which directly improves attendance for webinars, sales, and appointments.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You don't have to compare calendar URL formats by hand — paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why toUTC strips separators and milliseconds from an ISO string, and why Google/Yahoo need UTC dates in their URL while Outlook and Office 365 take a different parameter format entirely. The same assistant is useful for optimizing it — asking whether the .ics Blob and object URL cleanup in downloadIcs is handling the revokeObjectURL timing correctly across browsers, or whether the menu's outside-click and Escape listeners could be consolidated. It's just as good for extending the button: ask it to add an RRULE line to the .ics output for recurring events, support multiple time zones with a VTIMEZONE block, or generate all five calendar links server-side from one event object shared with a confirmation email. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build an "add to calendar" dropdown button in plain HTML, CSS, and JavaScript — no libraries, supporting Google Calendar, Outlook, Office 365, Yahoo, and a downloadable .ics file, all generated from one shared event data object.
Requirements:
- A single JavaScript object holding the event's title, description, location, start time, and end time in local ISO format, used as the single source of truth for every calendar target.
- A URL-building function that returns a correctly formatted link for each web provider: Google Calendar's render endpoint expects UTC timestamps in a single "dates" parameter joined by a slash; Yahoo expects separate start/end UTC parameters; Outlook and Office 365 use their own deeplink compose endpoints with different parameter names (startdt/enddt) and do not require the UTC conversion. Get each provider's specific parameter names and encoding right, not a single generic format.
- A UTC conversion helper that takes a local ISO datetime string and produces the compact YYYYMMDDTHHMMSSZ format required by calendar URLs and the .ics standard, by converting through the Date object's ISO output and stripping dashes, colons, and milliseconds.
- An .ics file generator that assembles a valid VCALENDAR/VEVENT block (with UID, DTSTAMP, DTSTART, DTEND, SUMMARY, DESCRIPTION, LOCATION using CRLF line endings), wraps it in a Blob with a text/calendar MIME type, creates a temporary object URL, triggers a download via a hidden anchor click, and revokes the object URL immediately after to avoid a memory leak.
- A dropdown trigger button with aria-haspopup and aria-expanded, a menu with role="menu" and role="menuitem" links, closing on outside click, Escape key, and after a selection is made — animated with opacity/transform only, never height or display toggling mid-transition.
- Web-provider menu items should open their generated URL in a new tab with rel=noopener; the .ics item should trigger the file download without navigating away from the page.Step by step
How to Use
- 1Paste HTML, CSS, and JSAn event card with an "Add to calendar" button renders. Click it to open the provider menu.
- 2Pick a providerChoose Google, Outlook, Office 365, or Yahoo — a pre-filled event opens in a new tab ready to save.
- 3Download the .icsChoose "Apple / .ics file" to download a universal calendar file that imports into Apple Calendar or any client.
- 4Edit the event detailsUpdate the EVENT object's title, description, location, start, and end — every provider link and the .ics rebuild from it.
- 5Check the timezoneAuthor start/end in local ISO time; toUTC() converts them to the UTC format calendars require automatically.
- 6Drop it into your pagePlace the button on an event, webinar, or booking confirmation page so attendees can save the date in one click.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Apple Calendar has no "add event" URL scheme, so a downloadable .ics file (the iCalendar standard) is the only way to support Apple users — and it works as a universal fallback for any calendar app on any platform. Offering web links for Google/Outlook/Yahoo plus the .ics means essentially every attendee can add your event in one click.
Author the start/end in local ISO time (e.g. 2026-07-12T18:30:00) and let toUTC() convert to the UTC YYYYMMDDTHHMMSSZ format calendars expect. For an event in a specific timezone that differs from the visitor's, include the timezone offset in the ISO string (…T18:30:00-04:00) so the conversion anchors to the right moment regardless of where the visitor is.
For the .ics file, add an RRULE line to the VEVENT (e.g. RRULE:FREQ=WEEKLY;COUNT=8 for eight weekly occurrences). The web-provider URLs have limited recurrence support, so for recurring events the .ics file is the most reliable option — most apps honor its RRULE on import.
In the .ics file, add a VALARM block inside the VEVENT (BEGIN:VALARM, ACTION:DISPLAY, TRIGGER:-PT30M, END:VALARM for a 30-minute-before reminder). Web-provider URLs generally don't accept reminder parameters, so reminders are an .ics-only feature on import.
In React, pass the event as a prop and compute the provider URLs with useMemo, generating the .ics in the click handler; in Vue, use a computed for the URLs; in Angular, use component methods. The URL-building and .ics-generation functions are framework-agnostic — only the dropdown open/close state moves into each framework's reactivity.