Create and apply custom themes to an Astro Starlight documentation site. Use when customizing colors, typography, or spacing via CSS custom properties, using the Tailwind CSS integration, applying light/dark mode variants, or loading custom fonts.
91%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Starlight exposes its entire visual design through CSS custom properties. Override any variable to change colors, typography, and layout — with or without Tailwind.
starlight-custom-component insteadStarlight styles live in CSS cascade layers. Unlayered CSS always wins.
--sl-* variables on :root to change every element that reads them. See css-variables-reference.md for the full list.@layer block is unlayered and automatically takes precedence over Starlight's named layers.@astrojs/starlight-tailwind compatibility package must be imported before Tailwind's own CSS or Starlight's styles break.Step 1 — Create the file:
/* src/styles/custom.css */
:root {
--sl-color-accent-low: #1a1a4e;
--sl-color-accent: #3d52d5;
--sl-color-accent-high: #b4bffe;
--sl-font: 'Inter', sans-serif;
--sl-content-width: 50rem;
}
:root[data-theme='dark'] {
--sl-color-bg: #0f172a;
}Step 2 — Register in astro.config.mjs:
starlight({
customCss: ['./src/styles/custom.css'],
})npx astro add tailwind
npm install @astrojs/starlight-tailwindReplace src/styles/global.css with:
@layer base, starlight, theme, components, utilities;
@import '@astrojs/starlight-tailwind';
@import 'tailwindcss/theme.css' layer(theme);
@import 'tailwindcss/utilities.css' layer(utilities);
@theme {
--font-sans: 'Inter';
--color-accent-500: var(--color-indigo-500);
/* Map full accent and gray scales — see references for complete example */
}Update astro.config.mjs:
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
integrations: [starlight({ customCss: ['./src/styles/global.css'] })],
vite: { plugins: [tailwindcss()] },
});See css-variables-reference.md for the full Tailwind @theme color scale mapping.
customCss arrayWHY: CSS files not registered in customCss are excluded from the Starlight build. Consequence: Styles are silently ignored.
BAD: Add a <style> block in a layout component.
GOOD: Register a CSS file in customCss in astro.config.mjs.
WHY: Tailwind's Preflight reset conflicts with Starlight's base styles. Consequence: Visual regressions, broken dark mode toggle.
BAD: Import tailwindcss without @astrojs/starlight-tailwind first.
GOOD: @import '@astrojs/starlight-tailwind' before Tailwind imports.
.dark class selectors for dark modeWHY: Starlight uses data-theme="dark" on <html>, not a .dark class. Consequence: Dark mode styles never activate.
BAD: .dark:bg-gray-900 (never matches in Starlight)
GOOD (plain CSS):
:root[data-theme='dark'] { --sl-color-bg: #0f172a; }Use dark: Tailwind variants only after installing @astrojs/starlight-tailwind.
--sl-* variables with Tailwind @theme overridesWHY: The two systems map to each other through @astrojs/starlight-tailwind. Setting both creates conflicting sources of truth. Consequence: Colors partially apply or behave differently in light vs. dark mode.
BAD: Set --sl-color-accent in CSS while also defining --color-accent-* in @theme.
GOOD: Choose one approach and apply all overrides through it.
font-display: swap in custom @font-faceWHY: Without it, browsers may block rendering until the font downloads. Consequence: Flash of invisible text (FOIT) on slower connections.
BAD: @font-face { font-family: 'X'; src: url('...'); }
GOOD: Add font-display: swap; to every @font-face.
WHY: Unlayered CSS always takes precedence over Starlight's named layers; a lower-priority layer can lose to Starlight's own rules. Consequence: Overrides silently lose.
BAD: @layer starlight { :root { --sl-color-accent: #3d52d5; } }
GOOD: Put the :root overrides in plain CSS with no @layer block.
WHY: @layer base, starlight, theme, components, utilities; fixes the cascade between Tailwind and Starlight. Consequence: Utilities and Starlight styles override each other unpredictably.
BAD: Start global.css with the Tailwind imports only.
GOOD: Start global.css with the @layer order line, then the imports.
WHY: Accent colours are a low, mid and high set. Consequence: Backgrounds, links and highlights mismatch in light and dark mode.
BAD: :root { --sl-color-accent: #3d52d5; } alone.
GOOD: Set --sl-color-accent-low, --sl-color-accent and --sl-color-accent-high together.
WHY: Replacing markup needs component overrides, which CSS variables cannot do. Consequence: Fragile selectors that break on Starlight updates.
BAD: Hide the sidebar with CSS and rebuild it by hand.
GOOD: Use starlight-custom-component to override the component.
| Topic | Reference | When to Use |
|---|---|---|
| CSS variables | CSS Variables Reference | Looking up --sl-* variables and the Tailwind @theme scale mapping |
| Styling guide | CSS & Styling Guide | Learning the official theming flow |
| Source variables | Starlight CSS variables (props.css) | Checking the full variable list |
| Colour editor | Color Theme Editor | Generating accent and gray scales |
| Fonts | Fontsource | Self-hosting custom fonts |
pantheon-org/tekhne
9aa89e5
Also appears in
last in sync Aug 28, 2026
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.