Embed in Next.js
Same shape as the React guide, in App Router terms: the page is a
"use client" component that calls
window.BookingWidget.mount() from an effect. The widget itself is
server-rendering-agnostic — it only ever runs in the browser, inside its own Shadow
DOM.
This is the complete examples/next/app/page.tsx host from the repo,
verbatim:
"use client";
import { useEffect, useRef } from "react";
// The Next host loads the IIFE bundle (layout) and mounts it from a client
// component — the widget (Preact, shadow DOM) is independent of Next/React.
declare global {
interface Window {
BookingWidget?: {
mount(el: HTMLElement, cfg: { apiBase: string; publishableKey: string; tripTypeId?: string }): () => void;
};
}
}
const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? "http://localhost:3010";
const PK = process.env.NEXT_PUBLIC_PK ?? "";
export default function Page() {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (ref.current && window.BookingWidget) {
return window.BookingWidget.mount(ref.current, { apiBase: API_BASE, publishableKey: PK });
}
}, []);
return (
<main style={{ maxWidth: 720, margin: "0 auto", padding: "40px 16px" }}>
<h1>Reel Time Charters — Next host</h1>
<p style={{ color: "#475569" }}>Mounted by a Next client component via the widget's mount() API.</p>
<div ref={ref} />
</main>
);
} Notes
-
Load
widget.global.jsonce inapp/layout.tsx(a plain<script>tag ornext/scriptwithstrategy="beforeInteractive") so the global exists before the effect fires. -
Config rides
NEXT_PUBLIC_*env vars in the example — both values are public by design (the publishable key is a public credential). -
Works under static export (
output: "export") — the example repo builds exactly that; there's no server dependency.
Want it to match your site? See Theming the widget.