Skills for setting up and customizing Astro Starlight documentation sites, covering project setup, custom theming, and component overrides.
100
100%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
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.
BAD: Add a <style> block in a layout component.
GOOD: Register a CSS file in customCss in astro.config.mjs.
Consequence: Styles are silently ignored.
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.
BAD: Set --sl-color-accent in CSS while also defining --color-accent-* in @theme.
GOOD: Choose one approach and apply all overrides through it.
Consequence: Colors partially apply or behave differently in light vs. dark mode.
font-display: swap in custom @font-faceWHY: Without it, browsers may block rendering until the font downloads.
BAD: @font-face { font-family: 'X'; src: url('...'); }
GOOD: Add font-display: swap; to every @font-face.
Consequence: Flash of invisible text (FOIT) on slower connections.