Skip to main content
Skip to main content

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 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)