TBX Docs
Customisation

Visual feedback

Optional third-party feedback widget on Vercel deployments

You can show a visual bug-reporting widget (Feedbucket, Marker, and similar) on a deployed textbook without editing index.html. Static builds are unchanged: opening index.html in a browser (or copying dist/) never loads the widget.

tbx update overwrites index.html, so the snippet must not live there. Put it in a Vercel environment variable instead. When Vercel builds the book, a Vite plugin inserts the snippet before </body> — the same gating as password protection (VERCEL_ENV is production or preview). This is not Routing Middleware: middleware cannot rewrite HTML, so injection happens at build time.

Enable on Vercel

  1. Copy the widget HTML from the vendor (usually a <script> tag).
  2. In the textbook's Vercel project, add an environment variable:
    • Name: TBX_FEEDBACK_SNIPPET
    • Value: the full HTML snippet (multiline is fine)
  3. Redeploy so the Vercel build picks up the value.

Do not prefix the variable with VITE_. That would embed the snippet in client JavaScript for every local build.

If the variable is unset or empty, nothing is injected.

Example: Feedbucket

Paste the Installation snippet from your Feedbucket project:

<script
  type="text/javascript"
  src="https://cdn.feedbucket.app/assets/feedbucket.js"
  data-feedbucket="YOUR_PROJECT_KEY"
  defer
></script>

That entire tag is the env var value. Swap vendors later by changing the variable and redeploying — no book code changes.

Do not commit a real project key in a public repo unless you intend the widget to appear for every visitor. Feedbucket can also gate the widget with a secret query parameter — see Feedbucket's visibility docs.

Local development and static builds

The snippet is not injected in:

  • vite dev / vite preview
  • npm run build output (dist/release and the ONE_FILE bundle)
  • Opening index.html from disk or any static host that is not Vercel

Even if you set TBX_FEEDBACK_SNIPPET in a local .env file, a local Vite build still skips it unless the process is a Vercel preview/production build.

Modals

Template modals treat third-party widgets as outside the dismiss layer, so clicking the widget does not close an open hotspot (or Notes / Help) dialog. Backdrop click, the close button, and Escape still close the modal.

Widgets that mount a custom element or iframe outside #root (the usual pattern) are recognized automatically.

Custom modals in a book

Import Modal from src/ui/library/Modal, not from @heroui/react, so isolation applies.

import { Modal } from "@/ui/library/Modal";

Existing books pick up the plugin and wrapper with tbx update, then set the env var and redeploy.

On this page