Skip to content

Standalone & Docs Site Integration

Standalone and Docs Site Integration

This guide covers two scenarios:

  1. Starlight docs site — integrating the widget into docs.theeducationalequalityinstitute.org (this site)
  2. 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-widget installed as a local dependency in teei-knowledge/docs/
  • Docs site running locally (pnpm dev in docs/)

Install the widget in the docs project

Terminal window
cd teei-knowledge/docs
pnpm add @teei/chat-widget@file:../chat-widget

Or in docs/package.json:

{
"dependencies": {
"@teei/chat-widget": "file:../chat-widget"
}
}

Then build the widget first:

Terminal window
cd teei-knowledge/chat-widget
pnpm build
cd ../docs
pnpm install

Add a custom Starlight head component

Starlight allows injecting custom content via head in astro.config.mjs. To load the widget CSS:

docs/astro.config.mjs
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/:

Terminal window
cp teei-knowledge/chat-widget/dist/styles.css teei-knowledge/docs/public/chat-widget.css

Add this to the docs site’s build script so it runs automatically:

docs/package.json
{
"scripts": {
"prebuild": "cp ../chat-widget/dist/styles.css public/chat-widget.css",
"build": "astro build"
}
}

Starlight renders a footer on every page. Override it to include the widget:

docs/src/components/DocsFooterWithChat.astro
---
// This overrides Starlight's default footer
import 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

Terminal window
cd teei-knowledge/docs
pnpm build
pnpm preview

Open 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:

astro.config.mjs
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

Terminal window
# 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:

  1. Add a mount() function to src/index.ts (recommended)
  2. Use the React CDN builds as shown above (simpler but loads React globally)
  3. 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