Skip to content

Kitchen Sink

This page exists to be themed, not to be read start to finish. It deliberately packs in every content surface Starlight renders — headings, lists, tables, asides, code blocks, and the built-in components — so that a single accent hue change or treatment swap can be checked against the whole site in one place.

Starlight Customizer supports bold text, italic text, and inline code in the same sentence, plus links to other pages and links to external sites. None of that is unusual for a docs site, but a customizer needs to get every one of those right at once, because a real page mixes them constantly.

Here is a paragraph long enough to wrap across several lines at a typical content width, which is exactly the kind of text a line-height or body-font-size control needs to be checked against. Starlight Customizer’s typography controls change the body font, the heading font, the monospace font, the base size, the type scale ratio, and the line height independently, and a short sentence or two rarely reveals whether a scale ratio has gone too aggressive — you need a paragraph like this one, with enough words per line to show where a font’s default line-height starts to feel cramped or airy once the base size changes underneath it.

An unordered list, with a nested sub-list:

  • Colors: accent hue and chroma, gray hue and chroma, five semantic hues
    • Role overrides: page background, nav background, sidebar background, text, link
    • Contrast floor: AA or AAA
  • Typography: body font, heading font, mono font, base size, scale ratio
  • Layout: content width, sidebar width, nav height, content gap, global radius, shadow elevation

An ordered list:

  1. Pick a preset or start from the Starlight default.
  2. Adjust colors, typography, and layout to taste.
  3. Choose treatments for each themeable component.
  4. Export theme.css and APPLY-THEME.md.

A loose list, where each item is its own paragraph:

  • The panel persists its state to localStorage on every change, since Starlight does a full page load between routes rather than a client-side transition.

  • The same state is also encodable into location.hash on demand, behind a “Copy share link” button, so a colleague can open an in-progress theme without you sending a file.

  • Import accepts either a pasted state.json or a pasted sidebar config, so migrating from a hand-written astro.config.mjs doesn’t require starting over.

Preset
A named bundle of control values that can be applied in one click, resetting every other value to that preset’s own defaults.
Treatment
A component-level style choice, such as “pill” versus “left bar” for the active sidebar item, implemented as a small set of alternative CSS rules rather than a continuous slider.
Emitter
The pure function that turns a ThemeState into a CSS string. It never touches the DOM or localStorage.

A theme editor that can’t show you the real page is just a color picker with extra steps.


Starlight’s table of contents in this fixture is configured for levels 2 through 4, so this heading and the one below it won’t appear in the “On this page” panel — but they still exist in the DOM, which matters for a customizer checking heading-level CSS in isolation from TOC filtering.

The smallest heading level Markdown supports. Real docs rarely go this deep, but the customizer’s typography scale still needs a value for it.

Houston, the Starlight mascot, floating against a starfield

Press Cmd + K on macOS, or Ctrl + K on Windows and Linux, to jump straight to the panel’s control search box.

What happens to my existing custom CSS?

It stays. The customizer writes into a single stylesheet loaded via Starlight’s customCss option; anything else you’ve added under src/styles/ continues to load exactly as before, and cascade layer ordering keeps your own rules able to override the generated ones if you set them up that way.

Control ID Group Type Default Min Max Step Tier Notes
color.accent.hue Colors range 250 0 360 1 1 Degrees on the OKLCH hue wheel
color.accent.chroma Colors range 0.12 0 0.4 0.01 1 Higher values look more saturated
type.font.body Typography font inter — — — 1 A Fontsource variable font id
layout.contentWidth Layout range 48 32 80 1 1.5 In rem
sidebar.activeStyle Sidebar select filled-pill — — — 2 One of 4 options
toc.currentStyle TOC select default — — — 2 One of 4 options
code.theme Code select starlight-default — — — build Approximated in preview only
page.toc.minLevel Page options range 2 1 6 1 build Approximated via DOM filtering
page.pagination Page options toggle true — — — build Hides .pagination-links when off
emit-css.js
export function emitCss(state, { forPreview = false } = {}) {
const lines = [headerComment()];
if (!forPreview) lines.push(...fontImports(state));
lines.push(...darkTokens(state), ...lightTokens(state));
return lines.join('\n');
}
Apply the exported theme
npm install @fontsource-variable/inter
cp theme.css src/styles/theme.css
git add src/styles/theme.css
git commit -m "Apply Starlight Customizer theme"
apply-preset.js
import { presets } from './presets.js';
import { setValue } from './state.js';
import { emitCss } from './emit-css.js';
export function applyPreset(state, presetId) {
const preset = presets.find((p) => p.id === presetId);
if (!preset) throw new Error(`Unknown preset: ${presetId}`);
return { ...state, values: { ...preset.values } };
return { ...state, preset: presetId, values: { ...preset.values } };
}
import { emitCss } from './customizer/core/emit-css.js';
import { defaultState, setValue } from './customizer/core/state.js';
const state = setValue(defaultState(), 'color.accent.hue', 260);
const css = emitCss(state);

Use Cmd + K to open the panel’s search box and jump straight to a control by name.

  1. Open the panel and pick a preset close to what you want, or start from Starlight Default.
  2. Adjust the accent hue, chroma, and any semantic hues you care about, watching the live contrast readout next to each color row.
  3. Switch to the treatments sections and choose an option for each themeable component: sidebar active style, TOC current item, asides, and so on.
  4. Open the export dialog and copy theme.css into src/styles/theme.css in your real project.
  5. Follow the remaining steps in the generated APPLY-THEME.md: install any fonts, add customCss to your Starlight config, and redeploy.
  • Directorysrc
    • Directorycontent
      • Directorydocs
        • index.mdx
        • Directoryguides
          • kitchen-sink.mdx
    • Directorycustomizer
      • Directorycore
        • manifest.js
        • state.js
        • emit-css.js
      • Directoryui
        • panel.js
        • controls.js
    • Directorycomponents
      • CustomizerFooter.astro
  • astro.config.mjs
  • package.json

Deterministic

The same ThemeState always emits byte-identical CSS, so exported stylesheets diff cleanly in version control.

Framework-free

No React, Vue, or Svelte — the panel is a single web component built from plain ES modules.

Reversible

Every control has a per-control reset, and the whole panel has a “Reset all” that returns to the active preset.

Get started Read the FAQ View on GitHub

Default: Default Default Default

Note: Note Note Note

Tip: Tip Tip Tip

Caution: Caution Caution Caution

Danger: Danger Danger Danger

Success: Success Success Success