Writing TypeScript Pages
Most pages in this documentation site are written in Markdown (.md) or
MDX (.mdx) — you write prose, and Starlight handles the layout, sidebar,
table of contents, and theming automatically.
But sometimes you need more control — a custom layout, interactive widgets, or
generated content. For those cases, you can write pages in TypeScript using
Astro’s .astro component format, while still getting the full Starlight shell
(header, sidebar, search, etc.).
When to Use TypeScript Pages
Section titled “When to Use TypeScript Pages”- Interactive demos — embed a live code editor, playground, or widget
- Dynamic content — generate tables or lists from data at build time
- Custom layouts — pages that don’t fit the standard prose format
- Computed documentation — API docs generated from source code
How It Works
Section titled “How It Works”-
Create an
.astrofile insrc/pages/Astro pages in
src/pages/get file-based routing just like content docs. For example,src/pages/my-custom-page.astrobecomes/my-custom-page/. -
Import the
StarlightPagelayout componentThis gives your page the full Starlight shell — sidebar, header, search, table of contents, and consistent theming.
-
Set frontmatter via the
frontmatterpropPass title, description, and other metadata the same way you would in Markdown frontmatter.
Minimal Example
Section titled “Minimal Example”Create a file at src/pages/docs/my-page.astro:
---// Summary: A custom TypeScript-authored documentation page that renders// inside the Starlight shell with full sidebar and theming support.
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';---
<StarlightPage frontmatter={{ title: 'My Custom Page', description: 'A page authored in TypeScript/Astro.', }}> <h2>Hello from TypeScript!</h2> <p> This page is written as an <code>.astro</code> component, but it looks and feels exactly like a Markdown page because it uses the <code>StarlightPage</code> wrapper. </p></StarlightPage>Visit it at: http://localhost:4321/docs/my-page/
Adding Interactive Components
Section titled “Adding Interactive Components”For client-side interactivity, use Astro’s island architecture. You can write components in React, Preact, Svelte, Vue, or Solid — and they hydrate only where needed.
Step 1: Install a Framework Integration
Section titled “Step 1: Install a Framework Integration”bunx astro add reactbunx astro add preactbunx astro add svelteStep 2: Write Your Component
Section titled “Step 2: Write Your Component”// Summary: A simple interactive React counter component demonstrating// client-side hydration in a Starlight documentation page.
import { useState } from 'react';
export default function Counter() { const [count, setCount] = useState(0);
return ( <div style={{ padding: '1rem', border: '1px solid var(--sl-color-gray-5)', borderRadius: '0.5rem' }}> <p>Count: <strong>{count}</strong></p> <button onClick={() => setCount(c => c + 1)}>Increment</button> <button onClick={() => setCount(0)} style={{ marginLeft: '0.5rem' }}>Reset</button> </div> );}Step 3: Use It in a Page
Section titled “Step 3: Use It in a Page”---import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';import Counter from '../../components/Counter';---
<StarlightPage frontmatter={{ title: 'Interactive Demo' }}> <h2>Live Counter</h2> <p>This counter is a React component hydrated on the client:</p> <Counter client:load /></StarlightPage>The client:load directive tells Astro to hydrate this component on page load.
Other options:
| Directive | When It Hydrates |
|---|---|
client:load |
Immediately on page load |
client:idle |
When the browser is idle |
client:visible |
When the component scrolls into view |
client:media |
When a CSS media query matches |
Using TypeScript in .astro Files
Section titled “Using TypeScript in .astro Files”The script block at the top of every .astro file (between the --- fences)
runs at build time and is full TypeScript:
---// This is TypeScript — runs at build timeinterface Person { name: string; role: string;}
const team: Person[] = [ { name: 'Alice', role: 'Lead' }, { name: 'Bob', role: 'Contributor' },];---
<ul> {team.map((p) => ( <li><strong>{p.name}</strong> — {p.role}</li> ))}</ul>File Organisation
Section titled “File Organisation”src/├── content/│ └── docs/ # Markdown / MDX pages (auto-routed by Starlight)│ ├── getting-started.mdx│ └── language/│ └── syntax.md├── pages/│ └── docs/ # TypeScript / Astro pages (manual routing)│ └── my-page.astro└── components/ # Reusable components (Astro, React, etc.) └── Counter.tsx- Consistent theming: Always wrap custom pages in
<StarlightPage>to get the standard header, sidebar, and styles. - SEO: Pass
titleanddescriptionin thefrontmatterprop. - Table of contents: Starlight auto-generates the TOC from
<h2>and<h3>elements inside<StarlightPage>— use semantic headings. - Sidebar: To add your custom page to the sidebar, include it explicitly in
astro.config.mjsunder the appropriate section’sitemsarray.