Last updated: First published:
Hooking into Starlight
This section describes how The Bag’s Starlight support hooks into the Starlight app.
Visit the corresponding section in the overview to see where we are in the big picture of The Bag’s Starlight support.
The way to enable view transitions on an Astro site is to add Astro’s <ViewTransitions />
component into the <head>
of every page. Starlight has a dedicated mechanism to insert elements into the <head>
. But that works for HTML elements, only. It can’t be used to insert an Astro component.
So we need to get access to an Astro component that can render the <ViewTransitions />
component into the <head>
. A good entry pont for that search is Starlight’s <Page>
component. Looking at the relevant part of that component see that the <head>
tag is inserted by the <Page>
component itself, but the children of the <head>
are rendered by a special <Head>
component provided by Starlight.
Overriding the <Head>
Component
We could copy Starlight’s original <Head>
component, insert the <ViewTransition>
component and then add our view transition enabled version to the components mapping in our astro.config.*
file. As our copy would be disconnected from future <Head>
improvements in Starlight, this is at best the second-best solution. It would make it necessary to repeat out change after every update to Starlight’s <Head>
component.
It is better to reuse the built-in component↗ as it is and just extend a bit around it.
So re-using and extending the <Head>
component is textbook.1 However, the vtbot
component wraps around the Starlight component, which enables the vtbot
component to insert stuff before and after the original header elements.
Now that the 👜 Bag of Tricks ✨ provides more components for Starlight, this file is also a good place to add them to enable more functionality for the Starlight website.
Structure of the Base Component
You might already have guessed, what astro-vtbot/components/starlight/Base.astro
might look like. It has to use <ViewTransitions />
and it must render its <slot/>
to insert the contents of the original Head
component.
The other parts you can see here are
- It includes
<ReplacementSwap>
to preserve Starlight’s app state - If an transition scope was defined for the main section, it inserts its name to the page for later reference, see Defining Animations
- It utilizes the
<StarlightConnector/>
component to sets up the connection to the Starlight app. This is described in more detail in the next section.
Connecting to Starlight
The <StarlightConnector>
is a component that only contains a single script.
Before we look deeper into what it does, you might ask:
? “Why is this an extra component?”
? “Why isn’t that script simply at the end of the Base component?”
Important question, you asked there! Scripts in the
Base
component would be executed before the scripts in the embedded components. Thus embedding the script into its own StarlightConnector component and putting that at the end of the component list ensures that the connector code only runs after the<ViewTransitions />
and<ReplacementSwap/>
scripts are loaded.
This in turn ensures that the event listeners are called in the intended order and that in turn determines the execution order of the callbacks ;-)
Three things might be interesting about the excerpt you see here:
-
There are some dependencies on the structure of Starlight’s page layout, the elements and classes used there, and how they are nested.
I’ve tried to keep that in check, make the assumptions explicit in the code, and find the right balance between purposefulness and flexibility. If the assumptions turn out to be wrong in future versions of Starlight, this is where I need to add support for multiple versions. -
You find here calls for all the features mentioned in the mandatory actions section.
-
If you do not only want to know what happens but also how, I refer you to the corresponding sections:
- Managing the App State for
markMainFrameForReplacementSwap
- Updating the Sidebar for
updateSidebar
andcloseMobileMenu
- Defining Transitions for
setMainTransitionScope
Footnotes
-
“Override the
<Head>
component as a last resort”, they said↗. Well, we are trained professionals, aren’t we? ↩