Shell Primitives
Additive primitives for loading fonts, publishing structured data, and improving keyboard navigation
Overview
These primitives help you wire page-level concerns without expanding your layout API.
FontAssets handles shared font-face declarations, JsonLd
emits structured data, and SkipLink gives keyboard users a fast path to
main content.
- Use them at the document shell layer, not inside leaf content components.
- They stay narrowly focused on rendering; route-specific decisions remain consumer-owned.
- Each primitive has an explicit accessibility, trust, or performance contract.
FontAssets
FontAssets injects the shared @font-face declarations used by
the Snurble typography tokens.
Contract
This primitive takes no props. Render it once in the document head.
Example usage
<Layout title="My Page">
<Fragment slot="head">
<FontAssets />
</Fragment>
<PageShell>
<!-- content that uses the shared font tokens -->
</PageShell>
</Layout>Consumer responsibilities
- Include it once per document to avoid duplicate font-face declarations.
- Use it alongside the font families referenced by
@matt-riley/design-tokens. - Account for the remote font origin in your performance and privacy review.
JsonLd
JsonLd renders a script[type="application/ld+json"] tag for
structured data in the head.
Contract
Pass a jsonld prop containing any JSON-serializable value. Values that
cannot be serialized cause the component to throw.
Example usage
const profileData = {
"@context": "https://schema.org",
"@type": "Person",
name: "Matt Riley",
jobTitle: "Software Engineer"
};
<Layout title="Profile">
<Fragment slot="head">
<JsonLd jsonld={profileData} />
</Fragment>
</Layout>Trusted boundary
The component escapes closing </ sequences before writing the script
contents. Consumers still own schema correctness, route placement, and ensuring the
input data is intentionally published.
SkipLink
SkipLink renders a hidden-until-focus anchor that helps keyboard users move
directly to the main content target.
Contract
Pass an internal anchor href beginning with #. Any other
value throws so the component cannot point to an unsafe or non-local target.
Example usage
<Layout title="My Page">
<SkipLink href="#main-content">Skip to main content</SkipLink>
<nav>
<!-- repetitive navigation -->
</nav>
<main id="main-content" tabindex="-1">
<!-- primary page content -->
</main>
</Layout>Accessibility responsibilities
- Place the skip link before repeated navigation or chrome.
- Ensure the destination element has a matching
id. - Add
tabindex="-1"to the destination when it is not normally focusable.
Try it
Press Tab at the top of this page to reveal the skip link and move focus to the example main landmark.
Composition Notes
Using the primitives together
A typical docs or marketing page renders FontAssets and
JsonLd in the head slot, then places SkipLink
as the first interactive element in the body. Add SeoMeta to the
head slot for Open Graph and Twitter Card metadata. Use
ServiceWorker for PWA registration. This keeps SEO, performance, and
keyboard affordances near the page shell instead of scattering them through content.
SeoMeta
Open Graph and Twitter Card metadata
Renders a <Fragment> of og: and
twitter: meta tags. Place it in the Layout head slot.
Both url and image must be absolute http/https
URLs; a non-absolute value throws at build time.
---
import { Layout, SeoMeta } from "@matt-riley/ui-astro";
---
<Layout title="My Page">
<SeoMeta
slot="head"
title="My Page"
description="Page description for social sharing"
url="https://example.com/my-page"
image="https://example.com/og.png"
siteName="My Site"
/>
</Layout>Props
title— page title (required)description— meta description (required)url— canonical absolute URL (required)image— absolute URL to OG image (optional)imageAlt— alt text for OG image; defaults to title (optional)type— OG type; defaults to"website"(optional)siteName— OG site_name (optional)twitterCard— Twitter card type; defaults to"summary_large_image"(optional)
ServiceWorker
PWA service worker registration
Registers a service worker on the load event. Guards with a
"serviceWorker" in navigator check so it is safe in all browsers.
Errors are reported via console.error.
---
import { Layout, ServiceWorker } from "@matt-riley/ui-astro";
---
<Layout title="My PWA">
<ServiceWorker src="/sw.js" scope="/" />
</Layout>Props
src— path to the service worker script; defaults to"/sw.js"(optional)scope— registration scope; defaults to"/"(optional)