Astro Starlight
Add Encatch documentation feedback to an Astro Starlight site using component overrides and React islands
Collect page-level feedback on every Starlight doc page: helpful votes, suggest an edit, and raise an issue. This guide follows the working example in get-encatch/astro-starlight-examples.
Overview
Starlight does not ship a layout hook for arbitrary footer widgets, so this integration overrides two built-in components:
| Starlight component | Purpose |
|---|---|
Footer | Renders the Encatch feedback row above the default footer (pagination, edit link) |
PageFrame | Mounts a small React island that initializes the Encatch Web SDK on each page |
The feedback UI is a React island (client:load) so it stays interactive while the rest of the page remains static Astro output.
What you'll need
- An Astro Starlight project (
@astrojs/starlightand@astrojs/react) @encatch/web-sdk1.4.0 or later- A publishable SDK key with your docs origin in Allowed Domains / Packages
- A published documentation feedback form in Encatch (combined form with logic jumps for helpful / suggest edit / raise issue)
Step 1: Install dependencies
In your Starlight project:
pnpm add @encatch/web-sdk @astrojs/react react react-dom lucide-react
pnpm add -D @types/react @types/react-domnpm install @encatch/web-sdk @astrojs/react react react-dom lucide-react
npm install -D @types/react @types/react-domyarn add @encatch/web-sdk @astrojs/react react react-dom lucide-react
yarn add -D @types/react @types/react-domEnable React and register Starlight component overrides in astro.config.mjs:
// astro.config.mjs
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import react from '@astrojs/react';
export default defineConfig({
integrations: [
react(),
starlight({
title: 'My docs',
customCss: ['./src/styles/encatch.css'],
components: {
Footer: './src/components/EncatchFooter.astro',
PageFrame: './src/components/EncatchPageFrame.astro',
},
}),
],
});Step 2: Configure environment variables
Copy these variables into .env (use the PUBLIC_ prefix so Astro exposes them to client code):
# Required
PUBLIC_ENCATCH_SDK_PUBLISHABLE_KEY=
PUBLIC_ENCATCH_DOCUMENTATION_FEEDBACK_FORM_SLUG=documentation_feedback
PUBLIC_ENCATCH_FEEDBACK_TYPE_QUESTION_SLUG=documentation_feedback_type
PUBLIC_ENCATCH_PAGE_URL_QUESTION_SLUG=page_url
PUBLIC_ENCATCH_HELPFUL_CHOICE_QUESTION_SLUG=helpful_question_choice
# Optional — leave blank for encatch.com defaults
PUBLIC_ENCATCH_API_HOST=
PUBLIC_ENCATCH_WEB_HOST=| Variable | Description |
|---|---|
PUBLIC_ENCATCH_SDK_PUBLISHABLE_KEY | Publishable key from Settings → Publishable SDK Keys |
PUBLIC_ENCATCH_DOCUMENTATION_FEEDBACK_FORM_SLUG | Slug of your combined documentation feedback form |
PUBLIC_ENCATCH_FEEDBACK_TYPE_QUESTION_SLUG | Hidden/routing question that selects helpful vs suggest-edit vs raise-issue |
PUBLIC_ENCATCH_PAGE_URL_QUESTION_SLUG | Question prefilled with the current page URL |
PUBLIC_ENCATCH_HELPFUL_CHOICE_QUESTION_SLUG | Yes/No question prefilled when the reader votes helpful |
The example repo ships a one-click Install form button in its README if you need the combined form created in your workspace automatically.
Step 3: Add SDK helpers
Create src/components/encatch.ts to initialize the SDK and open the combined form with the correct logic-jump prefills:
import { _encatch } from '@encatch/web-sdk';
import type { Theme } from '@encatch/web-sdk';
type DocumentationFeedbackRoute = 'page-helpful' | 'suggest-edit' | 'raise-issue';
function ensureEncatchInitialized(options?: { theme?: Theme }): boolean {
if (typeof window === 'undefined') return false;
const apiKey = import.meta.env.PUBLIC_ENCATCH_SDK_PUBLISHABLE_KEY?.trim();
if (!apiKey) {
console.warn('PUBLIC_ENCATCH_SDK_PUBLISHABLE_KEY is not set');
return false;
}
if (!_encatch._initialized) {
_encatch.init(apiKey, { theme: options?.theme ?? 'system' });
}
return true;
}
export function openHelpfulFeedbackForm(
pageUrl: string,
vote: 'yes' | 'no',
locale?: string,
) {
// Prefill feedback type, page URL, and yes/no — then showForm(formSlug)
// See full implementation in get-encatch/astro-starlight-examples
}
export function openSuggestEditForm(pageUrl: string, locale?: string) {
// Route to suggest-edit branch of the combined form
}
export function openRaiseIssueForm(pageUrl: string, locale?: string) {
// Route to raise-issue branch of the combined form
}The example repository contains the full openDocumentationFeedbackForm helper, host overrides, and locale sync.
Step 4: Build the feedback UI
Create src/components/DocsPageFeedback.tsx — a React footer row with helpful votes and action buttons:
import { useState } from 'react';
import { CircleAlert, Pencil, ThumbsDown, ThumbsUp } from 'lucide-react';
import {
openHelpfulFeedbackForm,
openRaiseIssueForm,
openSuggestEditForm,
} from './encatch';
export function DocsPageFeedback({ pageUrl, locale, helpfulQuestion, yes, no, suggestEdits, raiseIssue }) {
const [vote, setVote] = useState<'yes' | 'no' | null>(null);
const handleVote = (next: 'yes' | 'no') => {
const newVote = vote === next ? null : next;
setVote(newVote);
if (newVote) openHelpfulFeedbackForm(pageUrl, newVote, locale);
};
return (
<div className="encatch-feedback">
{/* Helpful question + Yes/No pills */}
{/* Suggest edits + Raise issue buttons */}
</div>
);
}Copy the complete component from the example repo.
Step 5: Override Starlight components
PageFrame — initialize the SDK
src/components/EncatchPageFrame.astro wraps the default frame and mounts EncatchInit as a client island:
---
import Default from '@astrojs/starlight/components/PageFrame.astro';
import { EncatchInit } from './EncatchInit';
const locale = Astro.currentLocale ?? 'en';
---
<Default>
<slot />
<Fragment slot="header"><slot name="header" /></Fragment>
<Fragment slot="sidebar"><slot name="sidebar" /></Fragment>
</Default>
<EncatchInit client:load locale={locale} />EncatchInit.tsx calls ensureEncatchInitialized() and syncEncatchLocale(locale) inside a useEffect.
Footer — render feedback on doc pages
src/components/EncatchFooter.astro renders the feedback row only on documentation pages:
---
import Default from '@astrojs/starlight/components/Footer.astro';
import { DocsPageFeedback } from './DocsPageFeedback';
const { entry, id } = Astro.locals.starlightRoute;
const locale = Astro.currentLocale ?? 'en';
const isDocPage = id !== undefined;
---
{isDocPage && (
<DocsPageFeedback
client:load
pageUrl={Astro.url.pathname}
pageTitle={entry.data.title}
locale={locale}
helpfulQuestion={Astro.locals.t('docsFeedback.helpfulQuestion')}
yes={Astro.locals.t('docsFeedback.yes')}
no={Astro.locals.t('docsFeedback.no')}
suggestEdits={Astro.locals.t('docsFeedback.suggestEdits')}
raiseIssue={Astro.locals.t('docsFeedback.raiseIssue')}
/>
)}
<Default><slot /></Default>Add docsFeedback.* strings to your Starlight i18n files under src/content/i18n/ (or hard-code labels while prototyping).
Step 6: Style the footer row
Add src/styles/encatch.css and reference it in starlight({ customCss: [...] }). Use Starlight CSS variables (--sl-color-text, --sl-color-gray-5, etc.) so the footer matches light and dark themes.
See encatch.css in the example repo for pill buttons, spacing, and border treatment.
Step 7: Run and verify
pnpm devOpen a doc page, click Yes or No, Suggest edits, or Raise issue, and confirm the Encatch modal opens with the page URL prefilled. Check responses in your Encatch dashboard under the linked form.
Domain allowlist
If the modal does not open, confirm your local or production docs URL is listed on the publishable key's Allowed Domains / Packages (for example localhost:4321 during development).
Next steps
- Route feedback to your team — Connect GitHub, Slack, or other destinations
- Customize the form — Edit questions and logic jumps in the Encatch dashboard
- Web SDK reference — Advanced APIs such as
addToResponse, locale, and theme: JavaScript Web SDK
Related links
Was this page helpful?