Standalone & Docs Site Integration
Standalone and Docs Site Integration
This guide covers two scenarios:
- Starlight docs site — integrating the widget into
docs.theeducationalequalityinstitute.org(this site) - Script tag — embedding the widget on any non-Astro HTML page without a build step
Part 1 — Starlight Docs Site Integration
The TEEI Knowledge Hub docs site (teei-knowledge/docs/) uses Astro Starlight. Starlight has a specific approach for adding custom components globally.
Prerequisites
@teei/chat-widgetinstalled as a local dependency inteei-knowledge/docs/- Docs site running locally (
pnpm devindocs/)
Install the widget in the docs project
cd teei-knowledge/docspnpm add @teei/chat-widget@file:../chat-widgetOr in docs/package.json:
{ "dependencies": { "@teei/chat-widget": "file:../chat-widget" }}Then build the widget first:
cd teei-knowledge/chat-widgetpnpm build
cd ../docspnpm installAdd a custom Starlight head component
Starlight allows injecting custom content via head in astro.config.mjs. To load the widget CSS:
import { defineConfig } from 'astro/config';import starlight from '@astrojs/starlight';
export default defineConfig({ integrations: [ starlight({ title: 'TEEI Knowledge Hub', // ... existing config
head: [ { tag: 'link', attrs: { rel: 'stylesheet', href: '/chat-widget.css', // Copied to public/ (see below) }, }, ],
// Custom components (see below) components: { Footer: './src/components/DocsFooterWithChat.astro', }, }), ],});Copy the widget CSS to public/
The simplest way to serve the widget CSS from the docs site is to copy it to docs/public/:
cp teei-knowledge/chat-widget/dist/styles.css teei-knowledge/docs/public/chat-widget.cssAdd this to the docs site’s build script so it runs automatically:
{ "scripts": { "prebuild": "cp ../chat-widget/dist/styles.css public/chat-widget.css", "build": "astro build" }}Create a custom Footer component with the chat widget
Starlight renders a footer on every page. Override it to include the widget:
---// This overrides Starlight's default footerimport Default from '@astrojs/starlight/components/Footer.astro';import { ChatProvider, ChatWidget } from '@teei/chat-widget';
// Detect language from the URL (Starlight route prefix)const lang = Astro.currentLocale ?? 'en'; // 'en' | 'uk' | 'no'---
<Default {...Astro.props}> <slot /></Default>
<ChatProvider client:idle apiUrl="https://knowledge-api.theeducationalequalityinstitute.org" platform="docs" userRole="public" language={lang}> <ChatWidget greeting="Hi! I can help you find information in the TEEI Knowledge Hub. Search isn't enough — just ask me directly. What do you need?" /></ChatProvider>Verify
cd teei-knowledge/docspnpm buildpnpm previewOpen http://localhost:4321/ — the TEEI chat FAB should appear at bottom-right on every Starlight page.
Alternative — Use the SiteConfig slot (Starlight 0.20+)
Starlight 0.20+ supports a SiteTitle slot component approach. If the Footer override causes issues, use the Head component override instead:
components: { Head: './src/components/DocsHeadWithChat.astro',}Part 2 — Script Tag Embedding (non-Astro sites)
For any HTML page that does not use Astro or a JS framework, the widget can be embedded via a pre-built script bundle.
This requires building a standalone UMD/IIFE bundle from the widget source. The current package ships ESM and CJS only. Use the following approach to create a standalone script:
Build the standalone bundle
# In teei-knowledge/chat-widget/npx esbuild src/index.ts \ --bundle \ --format=iife \ --global-name=TEEIChat \ --external:react \ --external:react-dom \ --outfile=dist/chat-widget.standalone.js \ --define:process.env.NODE_ENV='"production"'This creates dist/chat-widget.standalone.js that can be included via <script>.
Embed on any HTML page
<!DOCTYPE html><html><head> <!-- Widget styles --> <link rel="stylesheet" href="https://docs.theeducationalequalityinstitute.org/chat-widget.css" /></head><body>
<!-- Your page content -->
<!-- React (required peer dependency) --> <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script> <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<!-- TEEI Chat Widget standalone bundle --> <script src="https://docs.theeducationalequalityinstitute.org/chat-widget.standalone.js"></script>
<!-- Initialize the widget --> <div id="teei-chat-root"></div> <script> TEEIChat.mount('#teei-chat-root', { apiUrl: 'https://knowledge-api.theeducationalequalityinstitute.org', platform: 'website', userRole: 'public', language: 'en', }); </script>
</body></html>Note: The mount() API requires implementing a thin wrapper in src/index.ts that exposes an imperative mounting function. This is not yet part of the package — it needs to be added if standalone embedding is required.
Current limitation
The widget package currently exports React components only (ESM/CJS). For true script-tag embedding without React on the page, either:
- Add a
mount()function tosrc/index.ts(recommended) - Use the React CDN builds as shown above (simpler but loads React globally)
- Use a web component wrapper (most isolated but most work)
For the docs site, use the Astro component approach in Part 1 — the script tag approach is only needed for truly external HTML pages.
Starlight-specific tips
Starlight’s built-in search vs chat widget: Starlight includes Pagefind for local full-text search. The chat widget provides a different value — conversational answers, not search results. Both can coexist. Do not replace one with the other.
Dark mode: Starlight handles dark mode via a <html data-theme="dark"> attribute (or similar). The chat widget reads [data-theme="dark"] on the document root — it integrates with Starlight’s theme toggle automatically.
Sidebar width: Starlight’s sidebar takes up significant horizontal space at desktop widths. The chat panel (width: 400px by default) may partially overlap the content area on smaller desktop widths (1024–1280px). Override the panel width for the docs site:
/* In docs/src/styles/custom.css */.teei-chat-widget { --teei-chat-panel-width: 360px;}Page transitions: Starlight uses Astro’s view transitions. The chat widget, rendered via client:idle, persists across page transitions without re-mounting because the DOM node is the same across navigations (it’s in the Footer, which Starlight re-renders as a static element). If you find the widget re-mounting on each navigation, add transition:persist to the ChatProvider element:
<ChatProvider transition:persist client:idle ...> <ChatWidget /></ChatProvider>Verification checklist
Starlight docs site:
- Widget CSS loaded (check Network tab for
/chat-widget.css→ 200) - Chat FAB visible on every page at 1440px
- Dark mode toggle switches widget theme
- Language follows Starlight locale (
/en/,/uk/,/no/) - Widget survives page navigation (does not flicker or re-mount)
Script tag:
- React loads before the widget script
- Widget mounts in
#teei-chat-root - No CORS errors in browser console
-
userRole="public"confirmed in Network request payload