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&apos;s mount() API.</p>
      <div ref={ref} />
    </main>
  );
}

Notes

  • Load widget.global.js once in app/layout.tsx (a plain <script> tag or next/script with strategy="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.