Embed Zooza widgets (registration, calendar, profile, video, checkout, map) in any web app — as npm packages instead of copy-paste <script> snippets.
All packages are thin adapters around one core loader that reproduces the official embed mechanism exactly, and add what the snippets lack: unique ids (multiple widgets per page), clean unmount, SSR safety, TypeScript types and a Zooza-branded loading placeholder.
| Package | For | Usage |
|---|---|---|
@zooza/widgets-core |
Vanilla JS / any framework | loadWidget({ type, container }) |
@zooza/widgets-wc |
Plain HTML, WordPress, Angular, anything | <zooza-widget type="calendar"> |
@zooza/widgets-react |
React, Next.js (App Router ready) | <ZoozaWidget type="registration" /> |
@zooza/widgets-vue |
Vue 3, Nuxt | <ZoozaWidget type="checkout" /> |
@zooza/widgets-svelte |
Svelte 3/4/5, SvelteKit | <div use:zoozaWidget={{ type: 'map' }} /> |
Angular & Qwik: use @zooza/widgets-wc (custom elements work natively in both); dedicated wrappers are planned.
Every widget needs your company API key (the id value from your Zooza embed snippet, e.g. test123). The key is a public identifier — it ships in the page HTML to every visitor — so keeping it in NEXT_PUBLIC_* / VITE_* env vars is configuration hygiene, not security. Never put real secrets in widget config.
Set it once at app startup — initZooza is re-exported by every package:
import { initZooza } from '@zooza/widgets-react'; // or -vue, -svelte, -wc, -core
initZooza({
apiKey: import.meta.env.VITE_ZOOZA_API_KEY, // Next.js: process.env.NEXT_PUBLIC_ZOOZA_API_KEY
region: 'uk', // optional — omit for the default region
});Every widget on the page then works without per-widget config. Per-widget props/attributes override the global config when needed (e.g. multi-tenant admin previews).
Regions resolve to https://{region}.api.zooza.app — uk, asia today, any future region string works without a package update. Omit (or 'default') for https://api.zooza.app. apiUrl is a full override that beats region. Note: the API base is page-global (a <body> attribute in the embed contract) — one region per page.
npm install @zooza/widgets-reactimport { ZoozaWidget } from '@zooza/widgets-react';
export default function BookingPage() {
return <ZoozaWidget type="registration" />;
}npm install @zooza/widgets-vue<script setup>
import { ZoozaWidget } from '@zooza/widgets-vue';
</script>
<template>
<ZoozaWidget type="calendar" />
</template>npm install @zooza/widgets-svelte<script>
import { zoozaWidget } from '@zooza/widgets-svelte';
</script>
<div use:zoozaWidget={{ type: 'checkout' }}></div><script src="https://unpkg.com/@zooza/widgets-wc"></script>
<script>ZoozaWidgets.initZooza({ apiKey: 'test123' });</script>
<zooza-widget type="registration"></zooza-widget>Or as a module:
npm install @zooza/widgets-wcimport '@zooza/widgets-wc/register';npm install @zooza/widgets-coreimport { initZooza, loadWidget } from '@zooza/widgets-core';
initZooza({ apiKey: 'test123' });
const handle = loadWidget({
type: 'calendar',
container: document.querySelector('#booking'),
});
// later
handle.destroy();type |
Default version |
|---|---|
registration |
v1 |
profile |
v1 |
calendar |
v2 |
video |
v2 |
checkout |
v2 |
map |
v2 |
Common options (prop / attribute names vary slightly per framework — see package READMEs):
| Option | Default | Description |
|---|---|---|
type |
— (required) | Widget to embed |
apiKey |
from initZooza |
Company API key (public) — required here or via init |
version |
per-type (table above) | Widget API version override |
region |
from initZooza, else default |
API region: uk, asia, … → https://{region}.api.zooza.app |
apiUrl |
region-derived | Full API base URL override (beats region) |
widgetId |
zooza |
data-widget-id value (constant, leave alone) |
ref |
location.href |
Referrer URL reported to the widget API |
placeholder |
true |
Zooza-branded loading placeholder |
onLoad / onError |
— | Script lifecycle callbacks |
The packages reproduce the official Zooza embed snippet 1:1:
- set
data-zooza-api-urlon<body>, - insert an embedder
<script>whoseidis your company API key, plusdata-versionanddata-widget-idattributes, - insert the async widget script
{apiUrl}/widgets/{version}/?type={type}&ref={ref}before the embedder.
The remote script identifies your company by reading the embedder's id from the DOM (the key is never in the script URL), then renders the actual widget UI — these packages never reimplement it.
pnpm install
pnpm build # builds all @zooza/* packagesExamples live in examples/ — vanilla HTML, React + Vite, Next.js, Vue + Vite, Svelte + Vite. Run any of them with pnpm --filter example-react-vite dev (after pnpm build).
pnpm changeset # describe the change
pnpm version-packages # bump versions
pnpm release # build + publish all packagesAll @zooza/* packages are version-linked and published with public access.