Anatomy of a Mantine island
How a Markdown tag becomes a prerendered, rehydrated React component — the full journey from source to interactive widget.
Every interactive widget on this site — the cards, the accordions, the changelog timeline — starts life as a tag in a Markdown file. This post follows one of them from source to screen.
An island begins as either a tag like {% card %} or a
component('aardvark', 'card', …) call in a {% %} block — one implementation behind
both. At build time, the tag doesn’t render HTML directly; it emits a placeholder: a
wrapper element carrying a data-aardvark-island marker naming the component, with the
props serialized alongside. That marker is also your styling hook — CSS like
[data-aardvark-island="Card"] targets every rendered card on the site.
The client side is a single islands bundle, built with esbuild, that scans the page for those markers on load and mounts the matching React component — real Mantine components, with the theme palette seeded from your site’s SCSS colors.
The interesting part is what happens between build and load. With islands.ssr (on
by default), the build prerenders each island to static HTML using Node,
esbuild, and linkedom — so the actual widget markup is baked into the .html files. That
matters for three audiences: crawlers see real content instead of an empty div, no-JS
readers get a usable page, and everyone else gets a correct first paint instead of a
layout shift. When the client bundle loads, it re-renders the same component over that
markup, and the island becomes interactive.
The result is a static site that ships real HTML and also behaves like a React app where it counts. Browse the component library to see every island available, or read the changelog entry that introduced them.