Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save giuseppelt/7f918a3ac02a011d76811ae472f8bf09 to your computer and use it in GitHub Desktop.
Save giuseppelt/7f918a3ac02a011d76811ae472f8bf09 to your computer and use it in GitHub Desktop.
Astro Starlight builtin component override

Astro Starlight builtin component override

At the moment of writing, Astro Starlight is in prerelease stage and doesn't support layout extension capabilities.

But, we can easly work around that with a nasty hack. We can override Starlight builtin components with our own versions. For example we can

  • add something in the sidebar
  • replace the Footer
  • add something after the TableOfContent

Although, this guide involves Starlight, you can use this same hack with any Astro template and override their component.

How the Hack works

First of all you need to identify which component you want to override. So check the starlight source respository to see how they are structured. Then you create a component with the same name in your component override directory src/overrides/.

The trick is to use a vite plugin to resolve your version of the component, instead of the original one. You can provide the plugin with a simple astro-integration.

The full code of the plugin is down here.
Then you add the integration to your astro-config file, and you're set.

Now, you can just create component with the same name and they automatically replace the builtin ones.

Use cases

Total replacement

Suppose you want to change the Footer.astro component.

Just create a Footer.astro component inside src/overrides/.

---
---
<div>
This is my footer
</div>

Wrapping

You can still use original components. So you can wrap around them in order to keep them, but add something more.

For example you want to add a feedback component before the page navigation links (prev article, next article).

You need to create a PrevNextLinks.astro component inside src/overrides/, where you can import the builtin component.

---
import PrevNextLinks from "@astrojs/starlight/components/PrevNextLinks.astro";
import FeedbackComponent from "../FeedbackComponent.astro";
---
<>
    <FeedbackComponent />
    <PrevNextLinks {...Astro.props} />
</>

Credits

The full article of this solution is on the Feelback blog, which shows how to collect user feedback for your documentation pages. To achieve that, a Feedback component needed to be added to the layour page, so it will be present on every article. And hence this hack.

import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
import overrideIntegration from "./src/overrideIntegration.mjs";
export default defineConfig({
integrations: [
overrideIntegration(), // add the integration before starlight
starlight({
// ...everything else
})
]
})
import fs from "fs";
import path from "path";
// the directory where our component are located
const LOCAL_COMPONENT_DIR = "src/overrides";
/**
* @returns {import("astro").AstroIntegration}
* */
export default function overrideIntegration() {
return {
name: "overrides",
hooks: {
"astro:config:setup"({ updateConfig, config }) {
const components = fs.readdirSync("./" + LOCAL_COMPONENT_DIR).filter(x => x.endsWith(".astro"));
if (components.length === 0) {
console.warn("No local component found");
return;
}
updateConfig({
vite: {
plugins: [{
enforce: "pre",
name: "override",
async resolveId(source, importer) {
for (const component of components) {
if (source.endsWith(component) && !source.includes(LOCAL_COMPONENT_DIR) && !source.includes("node_modules")) {
if (importer.includes(LOCAL_COMPONENT_DIR)) {
return path.resolve("./node_modules/@astrojs/starlight/components/" + component);
} else {
return path.resolve("./" + LOCAL_COMPONENT_DIR + "/" + component);
}
}
}
}
}]
}
})
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment