Astrocal
Guides

Embeddable Widget

Drop-in booking widget for any website with one script tag.

Embeddable Widget

@astrocal/widget is a drop-in booking UI for any website. It renders a full calendar, time slot picker, and booking form inside a Shadow DOM — so it works on any page without CSS conflicts.

npm · GitHub

Installation

bash npm install @astrocal/widget
bash pnpm add @astrocal/widget
bash yarn add @astrocal/widget

html <script src="https://cdn.astrocal.dev/widget/latest/astrocal.js"></script>

Quick Start

Open a booking modal with one call:

import { open } from "@astrocal/widget";

open({
  eventTypeId: "your-event-type-id",
  mode: "popup",
});

Inline Mode

Mount the widget into a container element:

import { open, destroy } from "@astrocal/widget";

// Mount
open({
  eventTypeId: "your-event-type-id",
  mode: "inline",
  target: "#booking-container",
});

// Clean up when done
destroy("#booking-container");

CDN (No Build Step)

For sites without a bundler, load the widget via a script tag:

<script src="https://cdn.astrocal.dev/widget/latest/astrocal.js"></script>
<script>
  Astrocal.open({
    eventTypeId: "your-event-type-id",
    mode: "popup",
  });
</script>

Or use auto-initialization with data attributes — no JavaScript required:

<script src="https://cdn.astrocal.dev/widget/latest/astrocal.js"></script>
<div data-astrocal-event-type-id="your-event-type-id" data-astrocal-mode="inline"></div>

Configuration

PropertyTypeDefaultDescription
eventTypeIdstringrequiredEvent type UUID to display
apiUrlstring"https://api.astrocal.dev"API base URL
mode"inline" | "popup""popup"Render mode
targetstring | HTMLElementDOM element or CSS selector (inline mode)
timezonestringauto-detectedIANA timezone override
themeThemeConfigCSS custom property overrides
colorScheme"light" | "dark" | "auto""auto"Color scheme
demobooleanfalseDemo mode (mock data, no API calls)
onBookingCreated(booking: BookingResult) => voidBooking success callback
onError(error: WidgetError) => voidError callback
onClose() => voidPopup close callback

API

open(config)

Opens the booking widget. In popup mode, creates a modal overlay. In inline mode, mounts into the target element.

close()

Closes the popup widget if open. No-op if no popup is active.

destroy(target)

Destroys an inline widget mounted on a target element. Removes the Shadow DOM and cleans up all resources.

autoInit()

Scans the DOM for elements with data-astrocal-* attributes and mounts widgets automatically. Called automatically when using the CDN script tag.

Theming

Customize the widget appearance with CSS custom properties:

open({
  eventTypeId: "your-event-type-id",
  theme: {
    primaryColor: "#6366f1",
    primaryHoverColor: "#4f46e5",
    borderRadius: "12px",
    fontFamily: "Inter, sans-serif",
  },
});
PropertyCSS Custom PropertyDescription
primaryColor--astrocal-primaryPrimary action color
primaryHoverColor--astrocal-primary-hoverPrimary hover color
headingColor--astrocal-headingHeading text color
backgroundColor--astrocal-bgWidget background
textColor--astrocal-textBody text color
borderColor--astrocal-borderBorder color
borderFocusColor--astrocal-border-focusFocused border color
borderRadius--astrocal-radiusBorder radius
fontFamily--astrocal-fontFont family

The widget uses Shadow DOM isolation, so your site's styles won't affect it and vice versa.

SSR / Server-Side Rendering

The package is safe to import in Node.js (Next.js, Nuxt, etc.). The autoInit() function is guarded and will not run on the server. open() and destroy() require a browser environment. close() is a silent no-op on the server.

import { open } from "@astrocal/widget";

// Only call in browser context
if (typeof window !== "undefined") {
  open({ eventTypeId: "..." });
}

Using React? The @astrocal/react package wraps this widget with proper lifecycle management — mount, unmount, and prop updates are handled automatically.

Next Steps

On this page