HTML Page Layout Example
Minimal page structure with a header, optional sidebar, and a widget in the main area.
<!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>
<!-- additional page content -->
</div>
</main>
</body>
</html>
Load the script once in
<head>.Place
a-login-buttonanda-cart-modal-buttonin the header so they stay visible on all pages.Swap the panel for a page widget with
fullscreen="true"andnav-heightif booking should fill the viewport (see Full-Page Widgets below).
Full-Page Widgets
Use page widgets when the widget should behave like the main content area of the page.
Page widgets:
a-organization-pagea-organization-mapa-organization-calendara-resource-pagea-resource-mapa-resource-calendara-service-pagea-subscription-pagea-package-pagea-my-bookings
Recommended integration for full-page layouts
Use fullscreen="true" when the widget should fill the available viewport height. If your website has a sticky header, also pass nav-height so the widget does not render underneath it.
<a-resource-calendar
base-url="https://anny.co"
resource="my-resource"
fullscreen="true"
nav-height="72px"
></a-resource-calendar>
Notes:
fullscreen="true"maps toheight: 100vh.nav-heightchanges that tocalc(100vh - nav-height).If you set
height, auto-resize is disabled and the iframe becomes fixed-height.For
*-page, map, calendar, anda-my-bookings, full-height 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.
<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 organization map when the map is the primary UI. Use organization calendar when availability navigation is the primary UI. If you want the broader explore flow instead, use a-organization-page.
Panels
Booking panels are intentionally compact and keep navigation locked.
Panel widgets:
a-resource-booking-panela-service-booking-panel
Important behavior:
Panels always use dynamic height.
External
heightandfullscreenvalues are ignored.Panels are for embedding booking inside your own page layout.
<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 in Organization -> Settings -> Booking page -> Global components. They are meant to be shared controls, usually in a site header or sticky nav.
Login button
Use a-login-button when you want a shared login/logout control that stays in sync with the widget session.
<a-login-button
base-url="https://anny.co"
locale="en"
idp-uuid="your-idp-uuid"
></a-login-button>
Behavior:
Loads a dedicated login iframe.
Switches to the logged-in avatar state automatically.
Broadcasts auth changes so sibling widgets can refresh auth state.
Good placement:
Main site header
Mobile navigation drawer
Booking landing page top bar
Cart button
Use a-cart-modal-button when users can add items from booking widgets and later check out.
<a-cart-modal-button
base-url="https://anny.co"
modal-layout="drawer"
label="Cart"
></a-cart-modal-button>
Behavior:
Shows a live item-count badge.
Stays in sync with sibling widgets on the same page.
Opens checkout in a modal overlay.
Best pairing:
a-resource-booking-panelplusa-cart-modal-buttonMultiple booking widgets on one page with one shared cart trigger
Custom Events And Tracking
Most embed widgets forward booking lifecycle events as DOM custom events.
Supported event names:
view-pageadd-to-cartstart-checkoutcomplete-checkout
Common event payload fields:
event_namevaluegross_valuetaxcurrencytransaction_iditems
Example:
<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:
<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-buttonanda-cart-modal-buttonare utility widgets, not booking event emitters.Page widgets, maps, calendars, booking panels, and checkout-oriented pages emit booking events.
Subscription and package widgets emit checkout-focused events. In practice,
view-page,start-checkout, andcomplete-checkoutare the key ones there.
UTM Parameters And Click IDs
You do not need to do anything extra 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 |
| All (Google Analytics, etc.) |
| Google Ads |
| Meta / Facebook Ads |
| TikTok Ads |
| LinkedIn Ads |
This means that if a user arrives on your page via ?utm_campaign=spring&gclid=abc123, the widget will carry those values through to the booking and conversion tracking will work without any extra configuration.
No HTML attribute is needed — forwarding happens automatically on every widget load.
Start And End Dates
Most widgets accept start (and sometimes end) to pre-navigate the calendar or map to a specific date range.
ISO 8601 date string — exact date:
<a-resource-page
base-url="https://anny.co"
resource="my-resource"
start="2025-06-15"
></a-resource-page>
Relative keyword — resolved at render time:
Value | Meaning |
| Current day |
| Next day |
| Start of the current week |
| Start of next week |
| Start of the current month |
| Start of next month |
<a-resource-booking-panel
base-url="https://anny.co"
resource="my-resource"
start="tomorrow"
></a-resource-booking-panel>
Relative values are supported everywhere except 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 cover the most important ones.
Shared attributes for embed widgets
Applies to page widgets and panel widgets. Not applicable to button widgets.
Attribute | Purpose |
| Required. anny base URL, for example |
| Force widget language. If omitted, browser language is used |
| Fixed iframe height, for example |
| Fill viewport height ( |
| Offset from viewport top when using |
| Require login before booking |
| SSO identity provider UUID |
| Loading logo override |
All embed widgets also accept design attributes described in WIDGET_DESIGNING.md.
Organization widgets
a-organization-page
Attribute | Purpose |
| Required organization slug |
| Initial tab: |
|
|
|
|
| Initial start date (see Start and End Dates) |
| Initial end date |
| Preselect resource category |
| Hide resource headers |
| Hide organization header |
| Hide filter bar |
| Hide map switch or map area |
Important note:
In admin, the "calendar board" option maps to
calendar-view="list".
a-organization-calendar
Attribute | Purpose |
| Required organization slug |
|
|
| Category slug |
| Initial start date (ISO 8601 only) |
| Initial end date |
a-organization-map
Attribute | Purpose |
| Required organization slug |
| Initial start date (see Start and End Dates) |
| Initial end date |
| Hide resource headers |
| Hide organization header |
Resource widgets
a-resource-page
Attribute | Purpose |
| Required resource slug |
| Preselect service |
| Initial start date (see Start and End Dates) |
| Initial end date |
| Hide resource header |
| Hide organization header |
| Hide calendar |
a-resource-calendar
Attribute | Purpose |
| Required resource slug |
| Preselect service |
|
|
| Initial start date (ISO 8601 only) |
| Initial end date |
| Hide resource header |
| Hide organization header |
a-resource-map
Attribute | Purpose |
| Required resource slug |
| Preselect service |
| Initial start date (see Start and End Dates) |
| Initial end date |
| Hide resource header |
| Hide organization header |
a-resource-booking-panel
Attribute | Purpose |
| Required resource slug |
| Preselect service |
| Initial start date (see Start and End Dates) |
| Initial end date |
Service widgets
a-service-page
Attribute | Purpose |
| Required service slug |
| Optional resource preselection |
a-service-booking-panel
Attribute | Purpose |
| Required service slug |
| Optional resource preselection |
| Initial start date (see Start and End Dates) |
| Initial end date |
Subscription and package widgets
a-subscription-page
Attribute | Purpose |
| Required plan slug |
a-subscription-button
Attribute | Purpose |
| Required plan slug |
| Trigger label |
a-package-page
Attribute | Purpose |
| Required package slug |
a-package-button
Attribute | Purpose |
| Required package slug |
| Trigger label |
Button widgets
Applies to:
a-organization-buttona-resource-buttona-service-buttona-subscription-buttona-package-buttona-modal-buttona-cart-modal-button
Shared modal attributes
Attribute | Purpose |
|
|
|
|
| Custom dialog width, for example |
| Header title inside modal |
| Allow close on outside click |
| Show close button |
| Accessible label for modal dialog |
Trigger attributes for entity buttons
Applies to:
a-organization-buttona-resource-buttona-service-buttona-subscription-buttona-package-button
Attribute | Purpose |
| Default button text |
| Trigger width |
| Trigger background color |
| Trigger text color |
a-modal-button is different:
no
labelpropno built-in trigger styling props
use your own slotted element 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 non-button element.
<!-- Custom styled 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="#">Browse availability</a>
</a-organization-button>
<!-- a-modal-button requires a slotted trigger -->
<a-modal-button
base-url="https://anny.co"
resource="my-resource"
>
<button>Open booking</button>
</a-modal-button>
When a slot is provided, the label, button-background, button-text, and button-width trigger attributes are ignored. The click and keyboard handling is still managed by the widget wrapper.
a-resource-button
Attribute | Purpose |
| Required resource slug |
| Optional service preselection |
| Initial start date (see Start and End Dates) |
| Hide resource header |
| Hide organization header |
a-service-button
Attribute | Purpose |
| Required service slug |
| Optional resource preselection |
a-organization-button
Attribute | Purpose |
| Required organization slug |
| Initial organization tab |
|
|
|
|
| Hide resource header |
| Hide organization header |
a-modal-button
Use this for a hand-written modal trigger when you do not want an entity-specific button component.
Attribute | Purpose |
| Open a resource booking page |
| Preselect service when used with |
| Open organization explore page |
| Initial organization tab |
| Initial organization view |
| Initial organization calendar view |
| Hide resource header |
| Hide organization header |
Utility widgets
a-cart-modal-button
Attribute | Purpose |
| Button label |
| Accessible dialog label |
|
|
| Dialog size preset |
| Custom dialog width |
| Modal header title |
| Close on outside click |
| Show close button |
| Trigger width |
| Trigger height |
| Trigger background |
| Trigger text/icon color |
| Show or hide cart icon |
a-login-button
Attribute | Purpose |
| Login button locale |
| SSO provider UUID |
| Trigger width |
| Trigger height |
| Trigger background |
| Trigger text/icon color |
| Trigger border radius |
| Show or hide icon |
a-my-bookings
Attribute | Purpose |
| Loading placeholder text |
| Required |
| Optional locale |
| Fixed height |
| Full viewport height |
| Header offset for fullscreen |
| SSO entity ID |
| SSO provider UUID |
Important note:
a-my-bookingsalways requires authentication. It does not exposeshould-loginbecause login is mandatory.
Relative Date Shortcuts
Where start or end is supported, relative values can be used.
Supported values:
todaytomorrowthis_weeknext_weekthis_monthnext_month
Example:
<a-resource-booking-panel
base-url="https://anny.co"
resource="my-resource"
start="next_week"
></a-resource-booking-panel>
Practical Recommendations
Use the admin-generated snippet first, then refine manually only if needed.
Use page widgets for dedicated booking pages.
Use panels for custom editorial pages around the booking flow.
Use button widgets when booking should open on demand.
Put
a-login-buttonanda-cart-modal-buttonin stable shared UI positions so users can always find them.Prefer
drawerfor desktop side-panel checkout flows andfullscreenfor mobile-first experiences.
