> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anny.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Widget Embedding - Advanced

> This guide explains how to control layout, events, modal behavior, and HTML attributes in a targeted way.

## HTML page structure

A minimal page structure with a header, an optional sidebar, and a widget in the main area.

```html theme={null}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>My booking page</title>
  <script src="https://cdn.anny.co/widget/annyComponents.umd.latest.min.js"></script>
</head>
<body>

  <header>
    <a href="/">Your logo</a>
    <nav><!-- Navigation --></nav>
    <a-login-button base-url="https://anny.co"></a-login-button>
    <a-cart-modal-button base-url="https://anny.co" modal-layout="drawer"></a-cart-modal-button>
  </header>

  <main>
    <aside><!-- optional sidebar --></aside>

    <div>
      <a-resource-booking-panel
        base-url="https://anny.co"
        resource="my-resource"
      ></a-resource-booking-panel>

      <!-- further page content -->
    </div>
  </main>

</body>
</html>
```

* The script is loaded once in the `<head>`.
* `a-login-button` and `a-cart-modal-button` belong in the header, so they stay visible on all pages.
* Replace the panel with a page widget using `fullscreen="true"` and `nav-height` if the booking should fill the entire viewport height (see [Full-page widgets](#full-page-widgets) further below).

## Full-page widgets

Page widgets are suitable when the widget is the main content of the page.

Page widgets:

* `a-organization-page`
* `a-organization-map`
* `a-organization-calendar`
* `a-resource-page`
* `a-resource-map`
* `a-resource-calendar`
* `a-service-page`
* `a-subscription-page`
* `a-package-page`
* `a-my-bookings`

## Recommended integration for full-page layouts

Use `fullscreen="true"` so the widget fills the available viewport height. If your website has a fixed header, also pass `nav-height` so the widget is not rendered underneath it.

```html theme={null}
<a-resource-calendar
  base-url="https://anny.co"
  resource="my-resource"
  fullscreen="true"
  nav-height="72px"
></a-resource-calendar>
```

Notes:

* `fullscreen="true"` corresponds to `height: 100vh`.
* `nav-height` changes this to `calc(100vh - nav-height)`.
* If you set `height`, automatic resizing is disabled and the iframe has a fixed height.
* For `*-page`, map, calendar, and `a-my-bookings` widgets, full-page layouts are usually the cleanest integration.

## Organization map and organization calendar

These are page widgets, not modal buttons. Treat them like a full page section.

```html theme={null}
<a-organization-map
  base-url="https://anny.co"
  organization="my-org"
  fullscreen="true"
></a-organization-map>

<a-organization-calendar
  base-url="https://anny.co"
  organization="my-org"
  calendar-view="week"
  fullscreen="true"
></a-organization-calendar>
```

Use the organization map when the map is the primary interface. Use the organization calendar when availability navigation is the focus. If you want the full explore flow instead, use `a-organization-page`.

## Panels

Booking panels are deliberately kept compact and lock the navigation.

Panel widgets:

* `a-resource-booking-panel`
* `a-service-booking-panel`

Important behavior:

* Panels always use dynamic height.
* External `height` and `fullscreen` values are ignored.
* Panels are meant to embed the booking flow into your own page layout.

```html theme={null}
<a-service-booking-panel
  base-url="https://anny.co"
  service="intro-call"
></a-service-booking-panel>
```

## Login button and cart button

These two components are configured under Organization → Settings → Booking page → Global components. They are intended as shared controls that are usually located in the site header or in a fixed navigation bar.

### Login button

Use `a-login-button` when you need a shared login/logout element that stays in sync with the widget session.

```html theme={null}
<a-login-button
  base-url="https://anny.co"
  locale="en"
  idp-uuid="your-idp-uuid"
></a-login-button>
```

Behavior:

* Loads its own login iframe.
* Automatically switches to the logged-in avatar state.
* Forwards auth changes so neighboring widgets update their authentication state.

Good placements:

* Main site header
* Mobile navigation drawer
* Top bar on booking landing pages

### Cart button

Use `a-cart-modal-button` when users should add items from booking widgets and check out later.

```html theme={null}
<a-cart-modal-button
  base-url="https://anny.co"
  modal-layout="drawer"
  label="Cart"
></a-cart-modal-button>
```

Behavior:

* Shows a live badge with the item count.
* Stays in sync with neighboring widgets on the same page.
* Opens the checkout in a modal overlay.

Common combinations:

* `a-resource-booking-panel` together with `a-cart-modal-button`
* Several booking widgets on one page with a shared cart button

## Events and tracking

Most embed widgets forward booking lifecycle events as DOM custom events. This applies to everything except the login button.

Supported event names:

* `view-page`
* `add-to-cart`
* `start-checkout`
* `complete-checkout`

Common fields in the event payload:

* `event_name`
* `value`
* `gross_value`
* `tax`
* `currency`
* `transaction_id`
* `items`

Example:

```html theme={null}
<a-resource-page
  id="booking-widget"
  base-url="https://anny.co"
  resource="my-resource"
></a-resource-page>

<script>
  const widget = document.getElementById('booking-widget')

  widget.addEventListener('complete-checkout', (event) => {
    const data = event.detail
    console.log('Checkout complete', data.transaction_id, data.gross_value, data.currency)
  })
</script>
```

GA4 example:

```html theme={null}
<script>
  const widget = document.getElementById('booking-widget')

  widget.addEventListener('complete-checkout', (event) => {
    const data = event.detail

    gtag('event', 'purchase', {
      currency: data.currency,
      value: data.gross_value ?? data.value,
      transaction_id: data.transaction_id,
      items: (data.items || []).map((item) => ({
        item_id: item.id,
        item_name: item.name,
        quantity: item.quantity,
        price: item.price,
      })),
    })
  })
</script>
```

Notes:

* `a-login-button` and `a-cart-modal-button` are helper widgets and do not send booking events.
* Page widgets, maps, calendars, booking panels, and checkout-focused pages send booking events.
* Subscription and package widgets send checkout-focused events. In practice, `view-page`, `start-checkout`, and `complete-checkout` are the most relevant.

### UTM parameters and click IDs

You don't need to do anything else for attribution. When a widget loads, it reads the query string of the **parent page URL** and automatically forwards these parameters into the embedded iframe:

| Parameter                                                             | Platform                             |
| --------------------------------------------------------------------- | ------------------------------------ |
| `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term` | All (Google Analytics, among others) |
| `gclid`                                                               | Google Ads                           |
| `fbclid`                                                              | Meta / Facebook Ads                  |
| `ttclid`                                                              | TikTok Ads                           |
| `li_fat_id`                                                           | LinkedIn Ads                         |

So if a user arrives on your page via `?utm_campaign=spring&gclid=abc123`, the widget carries these values through the entire booking flow. Conversion tracking works without any additional configuration.

No HTML attribute is required. The forwarding happens automatically on every widget load.

## Start and end date

Most widgets accept `start` (and sometimes `end`) to pre-navigate the calendar or map to a specific date range.

**ISO 8601 date string** for an exact date:

```html theme={null}
<a-resource-page
  base-url="https://anny.co"
  resource="my-resource"
  start="2025-06-15"
></a-resource-page>
```

**Relative keyword value** that is resolved at render time:

| Value        | Meaning                    |
| ------------ | -------------------------- |
| `today`      | Current day                |
| `tomorrow`   | Next day                   |
| `this_week`  | Start of the current week  |
| `next_week`  | Start of the next week     |
| `this_month` | Start of the current month |
| `next_month` | Start of the next month    |

```html theme={null}
<a-resource-booking-panel
  base-url="https://anny.co"
  resource="my-resource"
  start="tomorrow"
></a-resource-booking-panel>
```

Relative values are supported everywhere, **except** for `a-resource-calendar` and `a-organization-calendar`, which require ISO 8601.

`end` always expects an ISO 8601 date string.

## Customization options by widget type

This section documents the public HTML attributes. Admin-generated snippets usually already cover the most important ones.

### Common attributes for embed widgets

Applies to page widgets and panel widgets. Not applicable to button widgets.

| Attribute      | Purpose                                                                                           |
| -------------- | ------------------------------------------------------------------------------------------------- |
| `base-url`     | Required. anny base URL, e.g. `https://anny.co`                                                   |
| `locale`       | Force the widget language. If omitted, the browser language is used                               |
| `height`       | Fixed iframe height, e.g. `700px` or `80vh`. Disables automatic resizing. Not for button widgets. |
| `fullscreen`   | Fill the viewport height (`100vh`). Not for button widgets.                                       |
| `nav-height`   | Offset from the viewport edge when using `fullscreen`, e.g. `64px`                                |
| `should-login` | Require login before booking                                                                      |
| `idp-uuid`     | UUID of the SSO identity provider                                                                 |
| `logo-url`     | Custom logo for the loading animation                                                             |

All embed widgets additionally accept the design attributes from `WIDGET_DESIGNING.md`.

## Organization widgets

### `a-organization-page`

| Attribute                   | Purpose                                                              |
| --------------------------- | -------------------------------------------------------------------- |
| `organization`              | Required organization slug                                           |
| `default-list`              | Initial tab: `resources`, `services`, `subscriptions`, or `packages` |
| `view`                      | `grid`, `list`, or `calendar`                                        |
| `calendar-view`             | `day`, `week`, `month`, or `list`                                    |
| `start`                     | Initial start date (see [Start and end date](#start-and-end-date))   |
| `end`                       | Initial end date                                                     |
| `default-category`          | Preselect a resource category                                        |
| `hide-resource-header`      | Hide the resource header                                             |
| `hide-organization-header`  | Hide the organization header                                         |
| `hide-organization-filters` | Hide the filter bar                                                  |
| `hide-organization-map`     | Hide the map toggle                                                  |

Note:

* The "Calendar board" option in the admin corresponds to `calendar-view="list"`.

### `a-organization-calendar`

| Attribute       | Purpose                            |
| --------------- | ---------------------------------- |
| `organization`  | Required organization slug         |
| `calendar-view` | `day`, `week`, `month`, or `list`  |
| `category`      | Category slug                      |
| `start`         | Initial start date (ISO 8601 only) |
| `end`           | Initial end date                   |

### `a-organization-map`

| Attribute                  | Purpose                                                            |
| -------------------------- | ------------------------------------------------------------------ |
| `organization`             | Required organization slug                                         |
| `start`                    | Initial start date (see [Start and end date](#start-and-end-date)) |
| `end`                      | Initial end date                                                   |
| `hide-resource-header`     | Hide the resource header                                           |
| `hide-organization-header` | Hide the organization header                                       |

## Resource widgets

### `a-resource-page`

| Attribute                  | Purpose                                                            |
| -------------------------- | ------------------------------------------------------------------ |
| `resource`                 | Required resource slug                                             |
| `service`                  | Preselect a service                                                |
| `start`                    | Initial start date (see [Start and end date](#start-and-end-date)) |
| `end`                      | Initial end date                                                   |
| `hide-resource-header`     | Hide the resource header                                           |
| `hide-organization-header` | Hide the organization header                                       |
| `hide-calendar`            | Hide the calendar                                                  |

### `a-resource-calendar`

| Attribute                  | Purpose                            |
| -------------------------- | ---------------------------------- |
| `resource`                 | Required resource slug             |
| `service`                  | Preselect a service                |
| `calendar-view`            | `day`, `week`, `month`, or `list`  |
| `start`                    | Initial start date (ISO 8601 only) |
| `end`                      | Initial end date                   |
| `hide-resource-header`     | Hide the resource header           |
| `hide-organization-header` | Hide the organization header       |

### `a-resource-map`

| Attribute                  | Purpose                                                            |
| -------------------------- | ------------------------------------------------------------------ |
| `resource`                 | Required resource slug                                             |
| `service`                  | Preselect a service                                                |
| `start`                    | Initial start date (see [Start and end date](#start-and-end-date)) |
| `end`                      | Initial end date                                                   |
| `hide-resource-header`     | Hide the resource header                                           |
| `hide-organization-header` | Hide the organization header                                       |

### `a-resource-booking-panel`

| Attribute  | Purpose                                                            |
| ---------- | ------------------------------------------------------------------ |
| `resource` | Required resource slug                                             |
| `service`  | Preselect a service                                                |
| `start`    | Initial start date (see [Start and end date](#start-and-end-date)) |
| `end`      | Initial end date                                                   |

## Service widgets

### `a-service-page`

| Attribute  | Purpose                         |
| ---------- | ------------------------------- |
| `service`  | Required service slug           |
| `resource` | Optionally preselect a resource |

### `a-service-booking-panel`

| Attribute  | Purpose                                                            |
| ---------- | ------------------------------------------------------------------ |
| `service`  | Required service slug                                              |
| `resource` | Optionally preselect a resource                                    |
| `start`    | Initial start date (see [Start and end date](#start-and-end-date)) |
| `end`      | Initial end date                                                   |

## Subscription and package widgets

### `a-subscription-page`

| Attribute | Purpose            |
| --------- | ------------------ |
| `plan`    | Required plan slug |

### `a-subscription-button`

| Attribute | Purpose                     |
| --------- | --------------------------- |
| `plan`    | Required plan slug          |
| `label`   | Label of the trigger button |

### `a-package-page`

| Attribute | Purpose               |
| --------- | --------------------- |
| `package` | Required package slug |

### `a-package-button`

| Attribute | Purpose                     |
| --------- | --------------------------- |
| `package` | Required package slug       |
| `label`   | Label of the trigger button |

## Button widgets

Applies to:

* `a-organization-button`
* `a-resource-button`
* `a-service-button`
* `a-subscription-button`
* `a-package-button`
* `a-modal-button`
* `a-cart-modal-button`

## Common modal attributes

| Attribute           | Purpose                                   |
| ------------------- | ----------------------------------------- |
| `modal-layout`      | `dialog`, `drawer`, or `fullscreen`       |
| `modal-size`        | `sm`, `md`, or `lg` for the dialog layout |
| `modal-width`       | Custom dialog width, e.g. `80vw`          |
| `modal-title`       | Title in the modal header                 |
| `close-on-backdrop` | Allow closing by clicking outside         |
| `show-close-button` | Show the close button                     |
| `aria-label`        | Accessible label for the modal dialog     |

## Trigger attributes for entity buttons

Applies to:

* `a-organization-button`
* `a-resource-button`
* `a-service-button`
* `a-subscription-button`
* `a-package-button`

| Attribute           | Purpose                         |
| ------------------- | ------------------------------- |
| `label`             | Default label of the button     |
| `button-width`      | Width of the trigger            |
| `button-background` | Background color of the trigger |
| `button-text`       | Text color of the trigger       |

`a-modal-button` is different:

* no `label` prop
* no built-in trigger styling props
* use your own element in the slot as the trigger

## Custom trigger (slot)

All button widgets accept a default slot that replaces the built-in trigger. Use this when you want to style the trigger yourself or use a different element as the button.

```html theme={null}
<!-- Custom button as trigger -->
<a-resource-button
  base-url="https://anny.co"
  resource="my-resource"
>
  <button class="my-cta-button">Book a desk</button>
</a-resource-button>

<!-- Link as trigger -->
<a-organization-button
  base-url="https://anny.co"
  organization="my-org"
>
  <a href="#">View availability</a>
</a-organization-button>

<!-- a-modal-button always requires a slot trigger -->
<a-modal-button
  base-url="https://anny.co"
  resource="my-resource"
>
  <button>Open booking</button>
</a-modal-button>
```

When a slot is used, `label`, `button-background`, `button-text`, and `button-width` are ignored. Click and keyboard handling are still managed by the widget wrapper.

### `a-resource-button`

| Attribute                  | Purpose                                                            |
| -------------------------- | ------------------------------------------------------------------ |
| `resource`                 | Required resource slug                                             |
| `service`                  | Optional service                                                   |
| `start`                    | Initial start date (see [Start and end date](#start-and-end-date)) |
| `hide-resource-header`     | Hide the resource header                                           |
| `hide-organization-header` | Hide the organization header                                       |

### `a-service-button`

| Attribute  | Purpose                         |
| ---------- | ------------------------------- |
| `service`  | Required service slug           |
| `resource` | Optionally preselect a resource |

### `a-organization-button`

| Attribute                  | Purpose                           |
| -------------------------- | --------------------------------- |
| `organization`             | Required organization slug        |
| `default-list`             | Initial organization tab          |
| `view`                     | `grid`, `list`, or `calendar`     |
| `calendar-view`            | `day`, `week`, `month`, or `list` |
| `hide-resource-header`     | Hide the resource header          |
| `hide-organization-header` | Hide the organization header      |

### `a-modal-button`

Use this button when you need a custom modal trigger without an entity-specific button component.

| Attribute                  | Purpose                                        |
| -------------------------- | ---------------------------------------------- |
| `resource`                 | Open the resource booking page                 |
| `service`                  | Preselect a service (together with `resource`) |
| `organization`             | Open the organization explore page             |
| `default-list`             | Initial organization tab                       |
| `view`                     | Initial organization view                      |
| `calendar-view`            | Initial organization calendar view             |
| `hide-resource-header`     | Hide the resource header                       |
| `hide-organization-header` | Hide the organization header                   |

## Helper widgets

### `a-cart-modal-button`

| Attribute           | Purpose                             |
| ------------------- | ----------------------------------- |
| `label`             | Button label                        |
| `aria-label`        | Accessible dialog label             |
| `modal-layout`      | `dialog`, `drawer`, or `fullscreen` |
| `modal-size`        | Dialog size preset                  |
| `modal-width`       | Custom dialog width                 |
| `modal-title`       | Title in the modal header           |
| `close-on-backdrop` | Close by clicking outside           |
| `show-close-button` | Show the close button               |
| `button-width`      | Trigger width                       |
| `button-height`     | Trigger height                      |
| `button-background` | Trigger background                  |
| `button-text`       | Trigger text/icon color             |
| `show-icon`         | Show or hide the icon               |

### `a-login-button`

| Attribute             | Purpose                      |
| --------------------- | ---------------------------- |
| `locale`              | Language of the login button |
| `idp-uuid`            | UUID of the SSO provider     |
| `button-width`        | Trigger width                |
| `button-height`       | Trigger height               |
| `button-background`   | Trigger background           |
| `button-text`         | Trigger text/icon color      |
| `small-border-radius` | Trigger corner radius        |
| `show-icon`           | Show or hide the icon        |

### `a-my-bookings`

| Attribute    | Purpose                      |
| ------------ | ---------------------------- |
| `base-url`   | Required                     |
| `locale`     | Optional language            |
| `height`     | Fixed height                 |
| `fullscreen` | Fill the viewport height     |
| `nav-height` | Header offset for fullscreen |
| `idp-uuid`   | UUID of the SSO provider     |

Note:

* `a-my-bookings` always requires authentication. `should-login` is not available, since login is mandatory.

## Recommendations

* Use the admin-generated snippet first and only refine it manually when needed.
* Use page widgets for dedicated booking pages.
* Use panels for editorial pages around the booking flow.
* Use button widgets when booking should only become visible after a click.
* Place `a-login-button` and `a-cart-modal-button` in stable, clearly visible positions in the UI.
* Prefer `drawer` for desktop-side checkout flows and `fullscreen` for mobile experiences.
