# Booking Widget

Let visitors pick an available time and book a Google Calendar meeting — powered by your team availability and a Booking Form.

## Quick Start

Add the CSS, script, and one mount element to your page:

```
<link rel="stylesheet" href="https://myformconnect.io/booking-widget.css">
<script src="https://myformconnect.io/booking-widget.js" defer></script>

<div data-booking-widget
     data-form-uuid="your-form-uuid"
     data-api-base="https://myformconnect.io"
     data-branding-name="MyFormConnect"
     data-branding-url="https://myformconnect.io"
     data-meeting-title="Book a Call"
     data-meeting-description="15-minute intro call"
     data-meeting-duration="15"></div>
```

Replace `your-form-uuid` with the UUID from your Booking Form (the same value in the form action `/f/…`). Use `data-branding-name` / `data-branding-url` for the “Powered by” link (MyFormConnect → https://myformconnect.io).

### Live availability

Slots come from your team’s weekly rules minus busy times on Google Calendar.

### Calendar invites

Confirmed bookings create a Google Calendar event with Meet when invite is enabled on the form.

### Domain protection

Slots only load when Domain Restriction is on and the request Origin/Referer host is whitelisted (ports ignored). Add `localhost` or `127.0.0.1` for local testing; `file://` pages are allowed when Origin is opaque `null`.

## Before you embed

1. **Connect Google Calendar** for the team under Account → Integrations.
2. **Set team availability** (weekly windows and meeting length) on the team settings page.
3. Create or open a **Booking Form** and copy its **form UUID**.
4. On the form, enable: - **Send Google Calendar invite** (with Meet link) - **Domain Restriction** — whitelist every site that will host the widget (e.g. `https://www.yoursite.com`). For local work, add `localhost` or `127.0.0.1` (any port matches). Opening a bare HTML file (`file://`) is allowed via opaque Origin `null`.

        If invite is off, domain restriction is off, or the Origin/Referer is not allowed, the slots API returns an empty calendar (no error details). Fix the form settings if times never appear.

## How to Use

### 1. Include CSS and JavaScript

Use the absolute URLs for your MyFormConnect host:

```
<link rel="stylesheet" href="https://myformconnect.io/booking-widget.css">
<script src="https://myformconnect.io/booking-widget.js" defer></script>
```

### 2. Add the mount element

An empty `data-booking-widget` element is enough — the script builds the calendar UI for you.

```
<div data-booking-widget
     data-form-uuid="your-form-uuid"
     data-api-base="https://myformconnect.io"
     data-branding-name="MyFormConnect"
     data-branding-url="https://myformconnect.io"
     data-meeting-title="Book a Call"
     data-meeting-description="15-minute intro call"
     data-meeting-duration="15"></div>
```

#### Data attributes

- `data-form-uuid` — **required**. Booking Form UUID.
- `data-api-base` — **required on external sites**. Your MyFormConnect API origin (e.g. `https://myformconnect.io`). Omit only when the widget runs on the same host as MyFormConnect.
- `data-branding-name` — brand label for the “Powered by” footer (e.g. `MyFormConnect`).
- `data-branding-url` — brand homepage URL for the “Powered by” link (e.g. `https://myformconnect.io`).
- `data-meeting-title` — heading shown in the widget (default: Meeting).
- `data-meeting-description` — short description on the confirm step.
- `data-meeting-duration` — display duration in minutes (actual slot length comes from team availability).
- `data-theme` — `auto` (default) blends with the host site; `mfc` uses MyFormConnect defaults.
- `data-slots-url` / `data-submit-url` — optional overrides for the API endpoints.

### 3. Theme and simple CSS overrides

By default the widget inherits your site’s font and text color, and picks up an accent from common CSS variables, `theme-color`, or nearby links/buttons. Pass one flag to lock MyFormConnect styling:

```
<div data-booking-widget
     data-theme="mfc"
     data-form-uuid="your-form-uuid"
     data-api-base="https://myformconnect.io"></div>
```

Override look with `--mfc-booking-*` CSS variables on `.mfc-booking`. One token applies to every similar surface (buttons, selected days, links, focus), so the widget stays coherent:

```
<style>
  .mfc-booking {
    --mfc-booking-accent: #0f766e;
    --mfc-booking-font: "Your Font", system-ui, sans-serif;
    --mfc-booking-radius: 0.75rem;
  }
</style>
```

#### Supported tokens

- `--mfc-booking-accent`, `--mfc-booking-accent-hover`, `--mfc-booking-accent-tint`, `--mfc-booking-accent-contrast`
- `--mfc-booking-font`, `--mfc-booking-text`, `--mfc-booking-heading`, `--mfc-booking-muted`, `--mfc-booking-faint`
- `--mfc-booking-surface`, `--mfc-booking-border`, `--mfc-booking-shadow`
- `--mfc-booking-radius`, `--mfc-booking-radius-sm`, `--mfc-booking-radius-pill`
- `--mfc-booking-danger`, `--mfc-booking-danger-bg`, `--mfc-booking-danger-border`
- `--mfc-booking-success`, `--mfc-booking-success-bg`

Prefer tokens over targeting individual parts — that keeps selection, primary actions, and links aligned with your brand color.

### 4. Optional: open from a button (popup)

Put the widget inside a popup overlay on your page, then open it with `data-booking-popup`:

```
<button type="button" data-booking-popup>Book a Call</button>

<div id="booking-popup-overlay" class="mfc-booking-popup" hidden aria-hidden="true">
  <div class="mfc-booking-popup-backdrop" data-booking-popup-close></div>
  <div class="mfc-booking-popup-panel" role="dialog" aria-modal="true">
    <button type="button" class="mfc-booking-popup-close" data-booking-popup-close aria-label="Close">×</button>
    <div data-booking-widget
         data-form-uuid="your-form-uuid"
         data-api-base="https://myformconnect.io"
         data-branding-name="MyFormConnect"
         data-branding-url="https://myformconnect.io"
         data-meeting-title="Book a Call"></div>
  </div>
</div>
```

The script listens for `data-booking-popup` clicks and Escape / close controls marked `data-booking-popup-close`.

## What gets submitted

On confirm, the widget `POST`s to `https://myformconnect.io/f/your-form-uuid` with fields your Booking Form expects, including:

| Field | Source |
| --- | --- |
| `name`, `email`, `company`, `message` | Visitor form |
| `preferred_date`, `preferred_time`, `timezone`, `duration` | Selected slot |
| `service_type`, `location_preference` | Defaults (Demo / Video Call) |
| `page_source` | Current page URL |

Make sure your Booking Form’s field mapping includes the date/time fields so calendar invites can be created.

## API endpoints

- `GET https://myformconnect.io/f/:form_uuid/slots` — availability JSON (gated by invite + domain restriction).
- `POST https://myformconnect.io/f/:form_uuid` — create the booking (same as a normal form submission).
- `GET https://myformconnect.io/booking-widget.js` — widget script.
- `GET https://myformconnect.io/booking-widget.css` — widget styles.

## Related

- [Form configuration](/docs/features/form-configuration) — domain restriction and form options
- [Using Loader.js](/docs/features/using-loader) — enhance regular HTML forms
