Vanilla JavaScript
One of our goals is to make the experience of using Fogbender without a framework as straightforward as possible.
Let’s go over our vanilla JavaScript example, available here—https://github.com/fogbender/fogbender-oss/tree/main/examples/vanilla—to explain how it works.
To see the demo in action, you can clone the repo and run the example locally:
(cd examples/vanilla && yarn && yarn start)
Then, open http://localhost:1234 in your browser.
Alternatively, you can open the example in CodeSandbox: https://codesandbox.io/p/sandbox/github/fogbender/fogbender-oss/tree/main/examples/vanilla.
The key thing to notice in index.html is display: flex
on the div wrapping <div id="app" />
:
<!DOCTYPE html><html> <head> <title>Parcel Sandbox</title> <meta charset="UTF-8" /> </head>
<body style="min-height: 100vh; display: flex; flex-direction: column; margin: 0"> <button id="button">Unmount</button>
<div style="flex: 1; display: flex"> <div id="app" /> </div>
<script type="module" src="src/index.ts"></script> </body></html>
We tried several approaches to make the Roomy widget fill all the space provided by its parent container, and Flexbox turned out to be the most sensible solution.
The bulk of src/index.ts
is taken up by token assembly:
import { createNewFogbender } from "fogbender";
const addFogbender = async (rootEl: HTMLElement) => { const clientUrl = "https://main--fb-client.netlify.app"; // This points to the demo environment - do not set `clientUrl` in production const token = { widgetId: "dzAwMTQ5OTEzNjgyNjkwNzA3NDU2", customerId: "org123", customerName: "Customer Firm", userId: "example_PLEASE_CHANGE", userEmail: "user@example.com", userJWT: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJleGFtcGxlX1BMRUFTRV9DSEFOR0UiLCJjdXN0b21lcklkIjoib3JnMTIzIiwiY3VzdG9tZXJOYW1lIjoiQ3VzdG9tZXIgRmlybSIsInVzZXJFbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VySWQiOiJleGFtcGxlX1BMRUFTRV9DSEFOR0UiLCJ1c2VyTmFtZSI6IkN1c3RvbWVyIFVzZXIifQ.upRXqWj7WOb-DcjqtJ_jJ96WShbx6npL8hboAurBhYg", userName: "Customer User", userAvatarUrl: "https://fogbender-blog.s3.us-east-1.amazonaws.com/fogbender-cardinal-closeup.png", // optional };
const fogbender = createNewFogbender(); fogbender.setClientUrl(clientUrl); // ⚠️ IMPORTANT: when using a token with your own widgetId, remove this fogbender.setToken(token); const cleanup = await fogbender.renderIframe({ rootEl, headless: false }); return cleanup;};
const run = async () => { const rootEl = document.getElementById("app"); const cleanup = await addFogbender(rootEl); document.getElementById("button").onclick = () => { cleanup(); };};
run();
Note: renderIframe()
returns a cleanup()
function that removes the widget from the DOM.
Otherwise, it’s fairly minimalist:
import { type Token, createNewFogbender } from "fogbender";
const addFogbender = async (rootEl: HTMLElement, token: Token) => { const fogbender = createNewFogbender();
fogbender.setToken(token);
const cleanup = await fogbender.renderIframe({ rootEl, headless: false });
return cleanup;};
const run = async () => { const rootEl = document.getElementById("app"); const token = ...; const cleanup = await addFogbender(rootEl, token); document.getElementById("button").onclick = () => { cleanup(); };};
run();
For an Intercom-style chat experience (button in lower right), use createFloatingWidget()
instead of renderIframe()
.
You can also show a standalone unread message badge using renderUnreadBadge()
. For example, you can place the unread badge next to a Support
link that leads to your support page.
Let’s take a look at all the options exposed by the Fogbender interface:
export interface Fogbender { // CONFIGURATION
// Required — sets the user/customer token setToken(token: Token | undefined): Promise<Fogbender>;
// Optional — sets light or dark theme setMode(mode: "light" | "dark"): Promise<Fogbender>;
// METHODS
// Renders unread message badge into a target DOM element renderUnreadBadge(opts: { el: HTMLElement }): Promise<() => void>;
// Renders messaging widget (iframe) into a target DOM element renderIframe(opts: { rootEl: HTMLElement; headless?: boolean; disableFit?: boolean; onBadges?: (badges: Badge[]) => void; }): Promise<() => void>;
// Renders floating widget (Intercom-style bubble in bottom right) createFloatingWidget(opts?: { verbose?: boolean; openInNewTab?: boolean; closeable?: boolean; defaultOpen?: boolean; }): Promise<() => void>;
// Check whether the widget is ready to render (token + URL configured) isClientConfigured(): Promise<Snapshot<boolean>>;
// INTERNAL / DEV OPTIONS setClientUrl(url: string | undefined): Promise<Fogbender>; setVersion(tag: string, version: string): Promise<Fogbender>; setEnv(env: Env | undefined): Promise<Fogbender>;}
For more on configuration options and token structure, see the Widget configuration section.