@goai/elements
v0.50.0
Published
Go AI embeddable AI agent elements for the browser. Six chat layouts (floating / inline / modal / drawer / page / standalone) plus an iframe wrapper. Shadow-DOM-isolated, streaming SSE.
Maintainers
Readme
Go AI Elements
Embeddable AI agent elements for go.ai. A library of browser elements — Web Components and a programmatic API — that drop your AI agent into any website. Five layout variations of the chat element ship today (floating launcher, inline block, modal, full-page, standalone) plus an iframe wrapper for strict isolation. Shadow-DOM-isolated, streaming SSE, zero React in the bundle.
Full documentation: https://go.ai/docs/elements
This README is a quick-start. Configuration reference, theming, lifecycle hooks, framework recipes, and the backend contract live on the docs site.
Identity
Every element requires both publicKey AND aiAgentDeploymentId.
Get them from your dashboard. The publicKey + secretKey flow is
server-to-server only (API SDK) — never use a secret in browser code.
Install
CDN (one-line script tag)
<script
src="https://cdn.go.ai/elements.js"
data-public-key="agent_pk_..."
data-ai-agent-deployment-id="..."
defer
></script>Boots the floating launcher in the bottom-right of the page. No further setup needed.
NPM
npm install @goai/elementsimport { mount } from "@goai/elements";
const agent = mount({
publicKey: "agent_pk_...",
aiAgentDeploymentId: "...",
mode: "inline",
target: document.getElementById("chat"),
});
agent.on("message", (m) => console.log(m));Web Component
<script type="module" src="https://cdn.go.ai/elements.js"></script>
<web-ai-chat
public-key="agent_pk_..."
ai-agent-deployment-id="..."
mode="inline"
style="display: block; height: 600px"
></web-ai-chat>The custom element observes attribute changes — flip mode, theme,
api-env, public-key, or ai-agent-deployment-id and the element
re-resolves at runtime.
Build catalog — every release ships every format
| File | Format | Use with |
| --------------------------------- | ------ | ---------------------------------------------- |
| elements.js | IIFE | Plain <script> (defines window.GoAI) |
| elements.esm.js | ESM | <script type="module"> import (CDN-friendly) |
| elements-web-component.esm.js | ESM | Same, registers <web-ai-chat> on import |
| index.mjs / web-component.mjs | ESM | Bundlers (Vite, webpack, esbuild) — bare imports kept |
| elements.cjs.js | CJS | require() from Node / legacy tooling |
| style.css | CSS | <link rel="stylesheet"> |
| schema.json | JSON Schema | Dashboard config UIs, backend handshake validation, 3rd-party tooling |
| schema.mjs | ESM | Zod runtime schemas: import { widgetConfigSchema } from "@goai/elements/schema" |
Every bundle exposes the same surface (mount, init, hook, types).
Pick whichever matches how your page loads scripts.
Standalone ESM bundle (browser-ready, no build needed)
elements.esm.js is a fully self-contained ESM bundle — every
dependency (preact, signals, streaming-markdown) inlined. Drop into
any page with <script type="module">. No bundler, no import map.
<script type="module">
import { mount } from "https://cdn.jsdelivr.net/npm/@goai/elements@latest/elements.esm.js";
mount({
publicKey: "agent_pk_...",
aiAgentDeploymentId: "...",
mode: "inline",
target: document.querySelector("#chat"),
});
</script>Web-component variant (self-registers <web-ai-chat> on import):
<script type="module">
import "https://cdn.jsdelivr.net/npm/@goai/elements@latest/elements-web-component.esm.js";
</script>
<web-ai-chat
public-key="agent_pk_..."
ai-agent-deployment-id="..."
></web-ai-chat>The brand CDN serves the same files:
https://cdn.go.ai/elements.js— IIFE (one-line<script>, notype="module")https://go.ai/elements.esm.js— standalone ESMhttps://go.ai/elements-web-component.esm.js— web-component ESM
Production tip. Pin a specific version (
@1.4.0, not@latest) so a published patch can't surprise you. jsDelivr caches per-version aggressively; pinned URLs are immutable and CDN-friendly.
+esmvselements.esm.js. jsDelivr's/+esmflag tries to auto-bundle on demand but trips on bare-specifier resolution for some packages.elements.esm.jsis pre-bundled at release time — always works, always immutable.
Framework integrations
React / Next.js / Preact
// app/_components/Chat.tsx
import { useEffect, useRef } from "react";
import type { ChatWidgetInstance } from "@goai/elements";
export function Chat() {
const containerRef = useRef<HTMLDivElement>(null);
const instanceRef = useRef<ChatWidgetInstance | null>(null);
useEffect(() => {
let alive = true;
import("@goai/elements").then(({ mount }) => {
if (!alive || !containerRef.current) return;
instanceRef.current = mount({
publicKey: "agent_pk_...",
aiAgentDeploymentId: "...",
mode: "inline",
target: containerRef.current,
});
});
return () => {
alive = false;
instanceRef.current?.destroy();
};
}, []);
return <div ref={containerRef} style={{ height: 600 }} />;
}Or just register the web component once and use it as JSX (React 19+ treats unknown tags as web components automatically):
import "@goai/elements/web-component";
export function Chat() {
return <web-ai-chat public-key="agent_pk_..." ai-agent-deployment-id="..." mode="inline" />;
}Vue 3
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from "vue";
import type { ChatWidgetInstance } from "@goai/elements";
const containerRef = ref<HTMLDivElement | null>(null);
let instance: ChatWidgetInstance | null = null;
onMounted(async () => {
const { mount } = await import("@goai/elements");
if (containerRef.value) {
instance = mount({
publicKey: "agent_pk_...",
aiAgentDeploymentId: "...",
mode: "inline",
target: containerRef.value,
});
}
});
onUnmounted(() => instance?.destroy());
</script>
<template>
<div ref="containerRef" style="height: 600px" />
</template>Vue treats <web-ai-chat> as a custom element automatically — no
config needed for unknown tags. To silence the dev warning, mark it
explicitly in vite.config.ts:
export default defineConfig({
plugins: [vue({ template: { compilerOptions: { isCustomElement: (t) => t.startsWith("web-ai-") } } })],
});Angular
// app.config.ts — allow custom elements
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core";
@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA] })
export class AppModule {}// chat.component.ts
import { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild } from "@angular/core";
@Component({
selector: "app-chat",
template: `<div #host style="height: 600px"></div>`,
})
export class ChatComponent implements AfterViewInit, OnDestroy {
@ViewChild("host", { static: true }) host!: ElementRef<HTMLDivElement>;
private instance: { destroy(): void } | null = null;
async ngAfterViewInit() {
const { mount } = await import("@goai/elements");
this.instance = mount({
publicKey: "agent_pk_...",
aiAgentDeploymentId: "...",
mode: "inline",
target: this.host.nativeElement,
});
}
ngOnDestroy() {
this.instance?.destroy();
}
}Svelte / SvelteKit
<script lang="ts">
import { onMount } from "svelte";
import type { ChatWidgetInstance } from "@goai/elements";
let host: HTMLDivElement;
let instance: ChatWidgetInstance | null = null;
onMount(async () => {
const { mount } = await import("@goai/elements");
instance = mount({
publicKey: "agent_pk_...",
aiAgentDeploymentId: "...",
mode: "inline",
target: host,
});
return () => instance?.destroy();
});
</script>
<div bind:this={host} style="height: 600px" />Vanilla / no-framework
<script type="module">
import { mount } from "https://cdn.jsdelivr.net/npm/@goai/elements@latest/elements.esm.js";
mount({
publicKey: "agent_pk_...",
aiAgentDeploymentId: "...",
mode: "inline",
target: document.querySelector("#chat"),
});
</script>
<div id="chat" style="height: 600px"></div>Element variations
| Variation | UX |
| ------------ | -------------------------------------------------------------------------------------- |
| floating | Floating launcher FAB + popover panel (default) |
| inline | Full chat block in page flow, sized to its container |
| modal | Centered modal window with dimmed backdrop. Page brings its own trigger button |
| page | Full viewport with sidebar (logo + nav + conversation list) |
| standalone | Full viewport, panel only (no sidebar) |
Plus an orthogonal iframe: true flag that wraps any of the above in
a same-origin iframe for strict JS + CSS isolation.
Pick at mount time via mode: '<value>' option or the mode="<value>"
attribute. See https://go.ai/docs/elements/modes.
Configuration
The element reads its per-deployment configuration from your
Go AI workspace at handshake time — colors, launcher
chrome, strings, action layout, model defaults, history visibility
all flow through StartConversationResponse.settings. You don't recompile
per-customer.
A handful of options live in the install snippet itself:
mount({
publicKey: "agent_pk_...",
aiAgentDeploymentId: "...",
presentation: { mode: "floating" },
baseUrl: "https://go.ai", // omit to use the brand default
user: { id: "u_123", email: "[email protected]" },
theme: "dark", // "auto" | "light" | "dark" | overrides object
i18n: { defaultLocale: "en" },
debug: "info", // optional — opens the structured log firehose
});Full option reference: https://go.ai/docs/elements/configuration.
Lifecycle hooks
import { hook } from "@goai/elements";
hook("*", "open", (inst) => analytics.track("agent_opened", { id: inst.widgetId }));
hook("*", "message", (inst, _event, msg) => console.log(msg.role, msg.text));The global object exposes the same API for non-bundled usage:
GoAI.hook("*", "*", (inst, event, data) => {
/* … */
});Full event map: https://go.ai/docs/elements/events.
Theming
Pass theme overrides at mount:
mount({
publicKey: "agent_pk_...",
aiAgentDeploymentId: "...",
theme: {
accent: "#10B981",
accentText: "#ffffff",
radius: "10px",
fontFamily: "Inter, system-ui, sans-serif",
},
});Or import the standalone stylesheet and style the host element yourself:
@import "@goai/elements/style.css";Full theming reference: https://go.ai/docs/elements/theming.
More framework recipes
WordPress, Webflow, Shopify, vanilla CMS, code playgrounds, MDX — https://go.ai/docs/elements/frameworks.
Browser support
Modern evergreens: Chrome / Edge ≥ 109, Firefox ≥ 110, Safari ≥ 16. iOS ≥ 16. No IE / Legacy Edge.
Links
License
MIT
