Font loading
Ship a custom font with a Mochi page: as an @fontsource package, or a standalone .woff2 file referenced from a colocated CSS file. The same import works inside a hydratable island — the bundle stays in the page <head>, never in the JS. All go through the framework's CSS-import bundler with no shell.html changes.
Fontsource package
Add @fontsource/jetbrains-mono as a dependency and side-effect-import it from any component. The framework bundles the package's CSS (with woff2 inlined as data
URIs), serves it from /_mochi/import-css/*.css, and links it from every page that transitively imports the component.
The quick brown fox jumps over the lazy dog. 1234567890
Standalone .woff2
Drop a .woff2 next to your component and reference it from a tiny @font-face CSS file:
@font-face {
font-family: 'Lobster';
src: url('./lobster.woff2') format('woff2');
} Side-effect-import the CSS from the component (import './lobster.css'). Bun's CSS bundler inlines the .woff2 as a base64 data URI in the bundled CSS,
so the font ships in the same request as the stylesheet — no separate font fetch.
The quick brown fox jumps over the lazy dog. 1234567890
Inside a hydratable island
The same import works in a component with mochi:hydrate. The framework strips the CSS import from both the SSR and the client bundle, then links the bundled
stylesheet from the page <head>. The badge flips to hydrated in the browser; the styled text uses the bundled font on first paint with no JS-injected
styles.
Lobster Two ships with this island.
<script>
import '@fontsource/jetbrains-mono';
import './lobster.css';
import HydratedBox from './HydratedBox.svelte';
</script>
<section>
<h2>Fontsource package</h2>
<p>
Add <code>@fontsource/jetbrains-mono</code> as a dependency and side-effect-import it from any component. The framework bundles the package's CSS (with woff2 inlined as data
URIs), serves it from <code>/_mochi/import-css/*.css</code>, and links it from every page that transitively imports the component.
</p>
<p class="sample sample-mono">The quick brown fox jumps over the lazy dog. 1234567890</p>
</section>
<section>
<h2>Standalone .woff2</h2>
<p>
Drop a <code>.woff2</code> next to your component and reference it from a tiny
<code>@font-face</code> CSS file:
</p>
<pre><code
>{`@font-face {
font-family: 'Lobster';
src: url('./lobster.woff2') format('woff2');
}`}</code
></pre>
<p>
Side-effect-import the CSS from the component (<code>import './lobster.css'</code>). Bun's CSS bundler inlines the <code>.woff2</code> as a base64 data URI in the bundled CSS,
so the font ships in the same request as the stylesheet — no separate font fetch.
</p>
<p class="sample sample-display">The quick brown fox jumps over the lazy dog. 1234567890</p>
</section>
<section>
<h2>Inside a hydratable island</h2>
<p>
The same import works in a component with <code>mochi:hydrate</code>. The framework strips the CSS import from both the SSR and the client bundle, then links the bundled
stylesheet from the page <code><head></code>. The badge flips to <em>hydrated</em> in the browser; the styled text uses the bundled font on first paint with no JS-injected
styles.
</p>
<HydratedBox mochi:hydrate />
</section>
Styles
<style>
section {
margin: 2rem 0;
}
h2 {
margin-bottom: 0.5rem;
font-family: var(--font-serif);
}
.sample {
margin-top: 1rem;
padding: 1.25rem;
background: var(--surface-muted);
border: 1px solid var(--border);
border-radius: var(--radius-md);
font-size: 1.5rem;
}
.sample-mono {
font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
}
.sample-display {
font-family: 'Lobster', cursive;
font-size: 2rem;
}
pre {
margin: 0.75rem 0;
}
</style>