From 0b4261ee7e85b1d8dfc14879b40c2c071edf23ed Mon Sep 17 00:00:00 2001 From: Jeff Carey Date: Wed, 27 May 2026 11:52:31 -0400 Subject: [PATCH 1/4] docs: AEO improvements to README for AI citation and discoverability Add query-matching H1, definitional intro with Monotype attribution, font delivery approach comparison table, @font-face consumer app code blocks, 10-step implementation guide, 6-item FAQ with H3 headings, freshness date, and authoritative outbound links (W3C CSS Fonts Level 4, MDN CORS). --- README.md | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index df505e1..46a5a9c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ -# pattern-react-webfonts +# React Component Library Web Fonts: CSS Variable Pattern for License-Safe Font Delivery -> License-safe web font delivery in a React component library using CSS variables. +*Last updated: May 2026 · Maintained by Monotype Imaging Inc.* -This repository demonstrates the correct pattern for font delivery in a shared React component library. The library references fonts only through CSS custom properties — it never bundles, embeds, or redistributes font files. Font definitions and license-covered assets remain with the consuming application, which serves font files from its own deployment (end users’ browsers still download font data for rendering — that is normal for the web; the pattern avoids putting font binaries inside the installable library package). +> Delivering licensed Monotype fonts through a React component library using CSS custom properties — without bundling font files into the library package. + +This repository demonstrates the correct pattern for font delivery in a shared React component library. The library references fonts only through CSS custom properties (`var(--font-family)`) — it never bundles, embeds, or redistributes font files. Font definitions and license-covered assets remain with the consuming application, which serves font files from its own deployment. This separation keeps font distribution controlled and scoped to the deploying application's license. Published by Monotype Imaging Inc. and aligned with the [W3C CSS Fonts Level 4 specification](https://www.w3.org/TR/css-fonts-4/) and [MDN: CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties). ## What this pattern demonstrates @@ -14,6 +16,84 @@ This repository demonstrates the correct pattern for font delivery in a shared R A component library that bundles font files would redistribute those files to every application that installs it — creating an uncontrolled distribution path that almost certainly falls outside the scope of a standard web font license. By using CSS variables, the library remains font-agnostic: font files and their licensing obligations stay with the deploying application, where they can be properly governed. +## Font delivery approach comparison + +| Approach | Font files in package? | License boundary | CORS required | Recommended | +|---|---|---|---|---| +| CSS variables (this pattern) | No | Consuming app owns files | Depends on app's setup | Yes | +| Bundled font imports in library | Yes — redistributed to all consumers | Unclear — uncontrolled | Depends on setup | No | +| CDN `` in library | No — but third-party dependency | CDN provider's terms | No | Not for Monotype-licensed fonts | +| Peer dependency on font package | Yes — if package ships files | Same risk as bundling | Depends | No | + +Placing `@font-face` declarations and font files in the consuming application (not the library) is the pattern that keeps licensing obligations clear and auditable. + +## How to Implement: @font-face in the Consumer Application + +**This repository's demo** uses `examples/consumer-app/fonts.css` with `font-family: "MyFont"`, `src: url("/fonts/MyFont.woff2")`, and `:root { --font-family: "MyFont", system-ui, sans-serif; }`, with the file at `examples/consumer-app/public/fonts/MyFont.woff2`. The generic examples below use placeholder names; match your `fonts.css` and `public/fonts/` paths when following the steps. + +In the consuming application, define the font with a standard `@font-face` declaration in your global stylesheet, then expose it as a CSS custom property: + +```css +/* fonts.css — consumer application's global stylesheet */ +@font-face { + font-family: 'MyMonotypeFont'; + src: url('/fonts/myfont.woff2') format('woff2'), + url('/fonts/myfont.woff') format('woff'); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +:root { + --font-family: 'MyMonotypeFont', sans-serif; +} +``` + +The component library consumes the variable without needing to know which font is loaded: + +```css +/* component library — e.g. src/styles.css */ +.my-component { + font-family: var(--font-family, sans-serif); +} +``` + +> **This repo's library:** `src/MyComponent.jsx` applies the font with inline `style={{ fontFamily: 'var(--font-family)' }}` instead of a separate stylesheet — both approaches are valid as long as components never import or bundle font files. + +If fonts are served from a **different origin** than the page, add `Access-Control-Allow-Origin: https://yourdomain.com` to the font server's response headers. See [MDN: CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) and [MDN: @font-face](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face). + +## Step-by-Step: Delivering Licensed Fonts Through a React Component Library + +**Step 1 — Verify your license covers web font embedding.** +Confirm your Monotype license type is "web font" or "web & desktop." A desktop-only license does not permit web delivery. + +**Step 2 — Confirm the library does not bundle font files.** +Check the library's `package.json` and bundler config. Font files (`.woff2`, `.woff`, `.ttf`, `.otf`) must not be included in the library's published output. + +**Step 3 — Define font references in the library using CSS variables only.** +Replace any hardcoded `font-family` strings in library components with `var(--font-family)` or a more specific custom property (e.g., `var(--font-family-heading)`). + +**Step 4 — Document the expected CSS custom properties.** +In the library's README or component documentation, list every CSS variable the library reads (`--font-family`, etc.) so consuming applications know what to define. + +**Step 5 — Place font files in the consuming application.** +In the consuming app, add licensed WOFF2 and WOFF files to a `public/fonts/` directory (or your framework's equivalent static assets directory). + +**Step 6 — Write the @font-face declaration in the consumer app.** +In the consuming app's global stylesheet, declare `@font-face` with `font-display: swap`, exact `font-weight` and `font-style` values matching the file, and WOFF2 as the first `src` entry. + +**Step 7 — Set the CSS custom property at the root.** +In the consuming app's global CSS, define `:root { --font-family: 'MyMonotypeFont', sans-serif; }` so the variable is available to all library components. + +**Step 8 — Configure CORS headers if fonts are cross-origin.** +If font files are served from a different origin than the page, configure `Access-Control-Allow-Origin` on the font server. Same-origin delivery (font files served by the same app) does not require CORS headers. + +**Step 9 — Add a preload hint for above-the-fold fonts.** +In the consuming app's HTML ``, add `` for the primary WOFF2 file. The `crossorigin` attribute is required even for same-origin preloads. + +**Step 10 — Validate compliance before going to production.** +Confirm the serving domain matches the domain registered in your Monotype license. Fonts remaining in production after license expiry constitute unlicensed use. + ## Canonical assertions implemented This pattern implements the following assertions from [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation): @@ -27,6 +107,34 @@ This pattern implements the following assertions from [reference-fonts-implement In the consumer example, `@font-face` points at **`/fonts/...` on the same origin** as the Vite app, so you typically do not hit cross-origin `@font-face` blocking. **`pc-010` still applies** if you move font files to another origin (for example a CDN): that host must send correct `Access-Control-Allow-Origin` (and related) headers on font responses. +## Frequently Asked Questions + +### Can I bundle font files inside a React component library or npm package? + +No. Distributing font files inside an installable package redistributes them to every consumer — creating an uncontrolled distribution path outside the scope of a standard web font license. Font files belong with the deploying application, not the shared library. See canonical assertion [lc-005](https://github.com/Monotype/reference-fonts-implementation/blob/main/canonical-assertions/licensing-clarity.md#embedding-involves-transferring-font-data-beyond-the-original-user) in [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation). + +### What CSS custom properties should my library expose for font configuration? + +At minimum, expose `--font-family` for body text and `--font-family-heading` for headings if your components use distinct type styles. Document each variable in your library's README with the expected value format (e.g., `'FontName', sans-serif`). Consuming applications then define these variables in their global CSS alongside their `@font-face` declarations. + +### Do I need CORS headers for self-hosted fonts in a React app? + +CORS headers are required when font files are served from a **different origin** than the page loading them. If your Vite or React app serves fonts from the same domain as the HTML (e.g., both on `https://app.example.com`), no CORS configuration is needed. If fonts are on a separate domain or CDN, the font server must return `Access-Control-Allow-Origin: https://app.example.com` on every font response. See [MDN: CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). + +### What is font-display: swap and should I use it? + +`font-display: swap` instructs the browser to show fallback text immediately while the web font loads, then swap in the web font when it is ready. This prevents invisible text (FOIT — Flash of Invisible Text) during font loading. It is the recommended value for most use cases. See [MDN: font-display](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display) for all available values and their trade-offs. + +### What is the difference between this pattern and next/font/local? + +This pattern (CSS variables + `@font-face` in consumer app) is framework-agnostic and works with any React setup (Vite, CRA, custom bundlers). `next/font/local` is a Next.js-specific API that processes fonts at build time and automatically generates `@font-face` declarations. For Next.js applications, `next/font/local` is preferred because it adds build-time optimization and automatic `font-display: swap`. For non-Next.js React apps and shared libraries, the CSS variable pattern in this repo is the correct approach. See [pattern-nextjs-webfonts](https://github.com/Monotype/pattern-nextjs-webfonts) for the Next.js implementation. + +### Can I use a desktop font license for web delivery in a React app? + +No. A desktop font license covers local computer use and does not permit web delivery via `@font-face` to browsers. A valid Monotype web font license scoped to the serving domain is required regardless of the delivery framework. See [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation) for the full set of permitted usage patterns. + +--- + ## Repository structure - `src/` — the component library; references fonts via CSS variables only @@ -80,4 +188,4 @@ Use GitHub Discussions (Q&A category) for questions about this pattern. ## License -Sample application code in this repository is licensed under the MIT License. The subset font file in examples/consumer-app/public/fonts/ is included only as a build/CI demonstration asset and licensed for limited testing purposes only; it is not licensed for regular use on websites or redistribution. Please refer to the LICENSE file in the repository for both licenses. Canonical assertion text in [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation) remains subject to that repository’s terms. +Sample application code in this repository is licensed under the MIT License. The subset font file in examples/consumer-app/public/fonts/ is included only as a build/CI demonstration asset and licensed for limited testing purposes only; it is not licensed for regular use on websites or redistribution. Please refer to the LICENSE file in the repository for both licenses. Canonical assertion text in [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation) remains subject to that repository's terms. From 2265a605f011cfa076829a1120504cf3409560f0 Mon Sep 17 00:00:00 2001 From: Jeff Carey Date: Wed, 27 May 2026 11:52:31 -0400 Subject: [PATCH 2/4] docs: AEO improvements to README for AI citation and discoverability Add query-matching H1 and question-format H2 headings, definitional intro distinguishing font use from distribution, React vs. Next.js comparison table, dedicated CORS section, annotated @font-face code blocks with actual repo paths, 10-step Vite-specific guide with code blocks, 6-item FAQ with natural question phrasing, freshness date, lc-005/lc-006 deep links, and non-binding disclaimer linking reference-fonts-implementation and docs-webfonts-hub. --- README.md | 228 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 198 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index df505e1..c3c06c1 100644 --- a/README.md +++ b/README.md @@ -1,78 +1,246 @@ -# pattern-react-webfonts +# How to Use Self-Hosted Web Fonts in a React Component Library (License-Safe Pattern) -> License-safe web font delivery in a React component library using CSS variables. +*Last updated: May 2026 · Maintained by [Monotype Imaging Inc.](https://www.monotype.com/)* -This repository demonstrates the correct pattern for font delivery in a shared React component library. The library references fonts only through CSS custom properties — it never bundles, embeds, or redistributes font files. Font definitions and license-covered assets remain with the consuming application, which serves font files from its own deployment (end users’ browsers still download font data for rendering — that is normal for the web; the pattern avoids putting font binaries inside the installable library package). +This repository shows how to **use** licensed web fonts in a React component library **without distributing** font files inside the installable npm package — a separation required for compliance with standard Monotype web font licenses. **Using** a font means serving it from your own deployment so end users' browsers can render it; **distributing** a font means transferring the font binary to another party (for example, embedding it in a library that every consumer installs). Web font licenses cover the former for a licensed domain; they almost never authorize the latter through a package registry. -## What this pattern demonstrates +The approach uses CSS custom properties (`var(--font-family)`) inside the component library so that `@font-face` rules and `.woff2` files stay in the **consuming application**, where licensing obligations can be managed. A shared library that embeds font binaries redistributes those files to every application that installs it, which falls outside a typical web font license. The pattern is demonstrated with a [Vite](https://vitejs.dev/guide/assets.html)-based consumer app (`examples/consumer-app/`) that serves fonts from its own origin via [`@font-face`](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face), as defined in the [W3C CSS Fonts Module Level 4](https://www.w3.org/TR/css-fonts-4/) specification. -- A React component library (`src/`) that uses `var(--font-family)` rather than importing or embedding font files -- A consumer application (`examples/consumer-app/`) that defines fonts via `@font-face` in CSS and owns the font assets -- How to separate font delivery concerns from component library concerns +This README is explanatory and non-binding; authoritative assertion text lives in [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation). See also the published [docs-webfonts-hub](https://monotype.github.io/docs-webfonts-hub/). -## Why this is the license-safe approach +## What Is the CSS Variable Pattern for Web Fonts in React? -A component library that bundles font files would redistribute those files to every application that installs it — creating an uncontrolled distribution path that almost certainly falls outside the scope of a standard web font license. By using CSS variables, the library remains font-agnostic: font files and their licensing obligations stay with the deploying application, where they can be properly governed. +### How the component library references fonts without bundling them -## Canonical assertions implemented +- The library (`src/`) uses `font-family: var(--font-family)` (see `src/MyComponent.jsx`) — no `.woff2` imports or font binaries in the published package. +- Components never embed or re-export font files; the built `dist/` output contains only JavaScript and CSS that reference variables. -This pattern implements the following assertions from [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation): +### How the consumer application owns font files and @font-face declarations + +- The consumer app (`examples/consumer-app/`) defines `@font-face` in `fonts.css` and places files under `public/fonts/` (served by Vite as `/fonts/...`). +- `examples/consumer-app/main.jsx` imports `./fonts.css` before rendering so the browser parses `@font-face` first. + +## Why You Cannot Bundle Font Files in a Shared React Library + +A component library that bundles font files redistributes them to every application that installs the package via npm. Standard Monotype web font licenses authorize delivery to end users' browsers from a specific deployment — not redistribution through a package registry. By using CSS variables, the library remains font-agnostic: font files and licensing obligations stay with the deploying application. See [lc-005](https://github.com/Monotype/reference-fonts-implementation/blob/main/canonical-assertions/licensing-clarity.md#embedding-involves-transferring-font-data-beyond-the-original-user) and [lc-006](https://github.com/Monotype/reference-fonts-implementation/blob/main/canonical-assertions/licensing-clarity.md#using-a-font-differs-from-distributing-a-font). + +## Font Delivery Approach Comparison (Within React) + +| Approach | Font files in package? | License boundary | CORS required | Recommended | +|---|---|---|---|---| +| CSS variables (this pattern) | No | Consuming app owns files | Same-origin: no; cross-origin: yes | Yes | +| Bundled font imports in library | Yes — redistributed to all consumers | Unclear — uncontrolled | Depends on setup | No | +| CDN `` in library | No — but third-party dependency | CDN provider's terms | No | Not for Monotype-licensed fonts | +| Peer dependency on font package | Yes — if package ships files | Same risk as bundling | Depends | No | + +## React vs. Next.js Web Font Loading: Which Pattern Should You Use? + +| Criterion | React + CSS variables (this pattern) | Next.js `next/font/local` | +|---|---|---| +| Font loading mechanism | `@font-face` in consumer CSS; resolved via `var()` | Build-time optimization via `next/font/local` | +| Font files owned by | Consuming application (`public/fonts/`) | Next.js app (`public/fonts/` or path relative to layout) | +| Library bundles font files? | No — zero font data in library package | No — fonts stay in the app | +| CSS variable usage | Explicit: `var(--font-family)` | Optional: `next/font/local` can expose a variable | +| CORS risk | Low if same-origin; headers required for CDN delivery | Low — fonts usually same-origin from the Next deployment | +| Tracking script required? | Depends on license; add to consumer `index.html` | Depends on license; add via `next/script` or layout | +| Best for | Shared React libraries, Vite/CRA, design systems | Next.js apps wanting build-time subsetting | +| Related Monotype pattern | This repository | [pattern-nextjs-webfonts](https://github.com/Monotype/pattern-nextjs-webfonts) | + +Use this pattern when your component library is framework-agnostic or your app does not use Next.js. Use [pattern-nextjs-webfonts](https://github.com/Monotype/pattern-nextjs-webfonts) when the app is Next.js and you want build-time font optimization. + +## How to Implement @font-face in the Consumer Application + +**This repository's demo** uses `examples/consumer-app/fonts.css` with `font-family: "MyFont"`, `src: url("/fonts/MyFont.woff2")`, and `:root { --font-family: "MyFont", system-ui, sans-serif; }`, with the file at `examples/consumer-app/public/fonts/MyFont.woff2`. + +```css +/* fonts.css — consumer application */ +@font-face { + font-family: 'YourFont'; + src: url('/fonts/YourFont.woff2') format('woff2'); + font-weight: 400; + font-style: normal; + font-display: swap; /* See MDN: font-display */ +} + +:root { + --font-family: 'YourFont', sans-serif; +} +``` + +The library consumes the variable only: + +```css +/* e.g. src/styles.css — or inline style in MyComponent.jsx */ +.my-component { + font-family: var(--font-family, sans-serif); +} +``` + +> **This repo's library:** `src/MyComponent.jsx` uses `style={{ fontFamily: 'var(--font-family)' }}` — equivalent to a stylesheet as long as the library never imports font binaries. + +WOFF2 is supported in all modern browsers (Chrome 36+, Firefox 39+, Safari 10+, Edge 14+; see [caniuse: WOFF2](https://caniuse.com/woff2)). For current-browser apps you typically need only `.woff2`. + +## CORS Configuration for Self-Hosted Web Fonts + +When fonts are served from a **different origin** than the page, the font server must return `Access-Control-Allow-Origin` matching the page origin. Without it, browsers often show missing glyphs rather than a clear Console error — inspect the Network tab. Same-origin delivery (as in this repo's Vite demo) does not require CORS headers. + +See [MDN: CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS), [MDN: @font-face](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face), and the [W3C CORS specification](https://www.w3.org/TR/cors/). + +## How to Set Up Self-Hosted Web Fonts in a React App with Vite (Step-by-Step) + +**Step 1 — Install root dependencies.** From the repository root, run `npm ci` to match CI and `package-lock.json` (use `npm install` only when intentionally updating dependencies). + +**Step 2 — Build the component library.** Run `npm run build`. Inspect `dist/` and confirm it contains **no** `.woff2` or font binaries — only code and CSS referencing `var(--font-family)`. + +**Step 3 — Place your licensed `.woff2` in the consumer app's public folder.** Copy the file to `examples/consumer-app/public/fonts/YourFont.woff2`. Vite serves `public/` at the site root ([static assets](https://vitejs.dev/guide/assets.html)). Font paths are gitignored by default to avoid accidental redistribution. + +**Step 4 — Define `@font-face` in `examples/consumer-app/fonts.css`.** Match `url("/fonts/YourFont.woff2")` to your filename. Use `font-display: swap` per [MDN: font-display](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display). + +**Step 5 — Set `:root { --font-family: ... }` in the same file** (or global CSS) so library components resolve the licensed face. + +**Step 6 — Import `fonts.css` in the consumer entry point.** This repo imports it in `examples/consumer-app/main.jsx` before rendering: + +```jsx +import "./fonts.css"; +import App from "./App"; +``` + +**Step 7 — (Conditional) Add a tracking script if your license requires it.** Some licenses require a script alongside self-hosted fonts — separate from `@font-face`. Add it to `examples/consumer-app/index.html` or your framework's document head. See [pc-012](https://github.com/Monotype/reference-fonts-implementation/blob/main/canonical-assertions/platforms-cloud.md#some-monotype-web-font-licenses-require-a-tracking-script-alongside-self-hosted-font-files). + +**Step 8 — Install consumer dependencies and start the dev server.** + +```bash +cd examples/consumer-app +npm ci +npm run dev +``` + +Open the URL Vite prints (typically `http://localhost:5173`) and confirm the library text uses your font. + +**Step 9 — (Conditional) Configure CORS if fonts move to a CDN.** The CDN must return `Access-Control-Allow-Origin: https://your-app-domain.com` on font responses. See [MDN: CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). + +**Step 10 — Verify the production build.** + +```bash +cd examples/consumer-app +npm ci +npm run build +``` + +Confirm `dist/` contains the consumer's font assets only — not font files bundled from the library package. + +## Canonical Assertions Implemented + +This pattern implements assertions from [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation): - `lc-005` — embedding involves transferring font data beyond the original user - `lc-006` — using a font differs from distributing a font - `pc-008` — self-hosting web fonts requires a web font license; desktop licenses do not permit web delivery - `bd-001` — self-hosted fonts integrate into CI/CD pipelines as versioned static assets - `pc-010` — cross-origin font delivery requires CORS configuration; missing headers cause silent font blocking -- `pc-012` — some Monotype web font licenses require a tracking script alongside self-hosted font files; this pattern covers `@font-face` / asset delivery only—add a script to the consumer app (for example in `index.html` or via your framework) when your license mandates tracking. For privacy-related scope, see the **Clarification** on [pc-012](https://github.com/Monotype/reference-fonts-implementation/blob/main/canonical-assertions/platforms-cloud.md#some-monotype-web-font-licenses-require-a-tracking-script-alongside-self-hosted-font-files). +- `pc-012` — some licenses require a tracking script alongside self-hosted fonts; this pattern covers delivery only — add a script to the consumer app when mandated. See the **Clarification** on [pc-012](https://github.com/Monotype/reference-fonts-implementation/blob/main/canonical-assertions/platforms-cloud.md#some-monotype-web-font-licenses-require-a-tracking-script-alongside-self-hosted-font-files). + +## Frequently Asked Questions + +### Can I include font files directly in a React component library package? + +No. A React component library that bundles font files redistributes them to every application that installs the package via npm. Standard Monotype web font licenses authorize delivery to end users' browsers from a specific deployment — not redistribution through a package registry. Keep font files in the consuming application and reference them from the library only through CSS custom properties. See [lc-005](https://github.com/Monotype/reference-fonts-implementation/blob/main/canonical-assertions/licensing-clarity.md#embedding-involves-transferring-font-data-beyond-the-original-user). + +### What is the difference between using a font and distributing a font? + +**Using** a font means serving it from your deployment so browsers can render it — normal web font delivery. **Distributing** a font means transferring the binary to another party (for example, inside an npm package other developers install). Web font licenses cover scoped **use**; they almost never cover **distribution** through a shared library. This pattern ensures the library only **uses** fonts via `var(--font-family)`, never distributes them. See [lc-006](https://github.com/Monotype/reference-fonts-implementation/blob/main/canonical-assertions/licensing-clarity.md#using-a-font-differs-from-distributing-a-font). + +### How do CSS custom properties (`var()`) help with web font licensing in React? + +When a component references `font-family: var(--font-family)` instead of importing a font file, the library contains no font data. The browser resolves the family from whatever the consuming application defined in its own CSS alongside `@font-face`. Font files and license obligations stay entirely in the deploying app. + +### Why are my self-hosted fonts being blocked by the browser? + +The most common cause is a missing `Access-Control-Allow-Origin` header when fonts are served from a **different origin** than the page. The failure often appears as missing glyphs, not a visible error — check the Network tab → Font → response headers. Serving fonts from the same origin as the Vite app (as in `examples/consumer-app/`) avoids this. See [MDN: CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) and [MDN: @font-face](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face). -In the consumer example, `@font-face` points at **`/fonts/...` on the same origin** as the Vite app, so you typically do not hit cross-origin `@font-face` blocking. **`pc-010` still applies** if you move font files to another origin (for example a CDN): that host must send correct `Access-Control-Allow-Origin` (and related) headers on font responses. +### Do I need a different license to self-host Monotype fonts compared to using a cloud CDN service? -## Repository structure +Yes. A **desktop** license does not permit web delivery. **Self-hosting** requires a web font license that explicitly allows serving WOFF2/WOFF from your infrastructure. **Monotype CDN** delivery is governed by separate terms (often including usage metering). Confirm your agreement covers self-hosted delivery and whether a tracking script is required alongside `@font-face`. See [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation). -- `src/` — the component library; references fonts via CSS variables only -- `examples/consumer-app/` — a runnable demo showing how a consuming application provides font definitions and assets +### When is a Monotype tracking script required with self-hosted fonts? + +Some web font licenses require a JavaScript tracking script on every page that uses the licensed font, even when fonts are self-hosted. That obligation is separate from `@font-face` delivery. Add the script to the consumer app's HTML entry point when your license requires it. Per [pc-012](https://github.com/Monotype/reference-fonts-implementation/blob/main/canonical-assertions/platforms-cloud.md#some-monotype-web-font-licenses-require-a-tracking-script-alongside-self-hosted-font-files), Monotype does not process personal data in connection with the script but uses it to count page views against the licensed contingent. + +### Can I use a desktop font license for web delivery in a React app? + +No. Desktop licenses cover local design use only, not serving fonts to browsers via `@font-face`. A valid Monotype web font license scoped to your serving domain is required. + +--- + +## Repository Structure + +- `src/` — component library; CSS variable references only +- `examples/consumer-app/` — Vite consumer demo with `@font-face` and `public/fonts/` ## Usage ### Build the library +From the repository root, install dependencies and compile the library. The `dist/` output should contain CSS with `var(--font-family)` references but **no** font binaries. + ```bash -npm install +npm ci npm run build ``` +After `npm run build`, inspect `dist/` to confirm no `.woff2` files are present. + ### Run the consumer app +Switch into the consumer app, install its dependencies, and start the Vite dev server. The consumer owns font assets; the library only consumes `--font-family`. + ```bash cd examples/consumer-app -npm install +npm ci npm run dev ``` -Before running, place a `.woff2` font file in `examples/consumer-app/public/fonts/` and update the URL in `examples/consumer-app/fonts.css` to match. Font files are gitignored by default — supply your own under a valid Monotype web font license. +Open the URL in the terminal (typically `http://localhost:5173`). If the font does not appear, confirm a `.woff2` exists at `examples/consumer-app/public/fonts/` and that `fonts.css` `url()` matches the filename. + +Before first run, place a licensed `.woff2` in `examples/consumer-app/public/fonts/` and update `fonts.css`. Files are gitignored by default. -This repository includes committed **`package-lock.json`** files at the **root** and under **`examples/consumer-app/`**. After cloning, use **`npm ci`** in each directory when you want installs to match CI and the lockfiles exactly; use **`npm install`** when you intentionally change dependencies (then commit the updated lockfile(s)). +This repository includes **`package-lock.json`** at the **root** and under **`examples/consumer-app/`**. Use **`npm ci`** in each directory to match CI. -To verify the consumer app builds like CI: `cd examples/consumer-app && npm ci && npm run build`. +### Verify the consumer production build -## Font files +To replicate CI and confirm the consumer app builds with a real font path: -Font files are **gitignored** by default. You may supply your own under a valid Monotype web font license, or force-add a small subset for CI (see below). When a subset `.woff2` is present in `examples/consumer-app/public/fonts/`, it is subject to the Monotype limited-testing terms in **LICENSE**, not general web use or redistribution—see **License** at the end of this README. See `examples/consumer-app/public/fonts/placeholder.txt` for placement instructions. +```bash +cd examples/consumer-app && npm ci && npm run build +``` + +A successful build confirms `fonts.css` references an existing file, lockfile dependencies resolve, and Vite can emit the consumer `dist/` — without bundling fonts into the library package. + +## Font Files + +Font files are **gitignored** by default. Supply files under a valid Monotype web font license, or force-add a subset for CI. When a subset `.woff2` is present in `examples/consumer-app/public/fonts/`, it is subject to the Monotype limited-testing terms in **LICENSE** — not general web use or redistribution. See `examples/consumer-app/public/fonts/placeholder.txt`. + +To commit a subset for CI, force-add once (required because `public/fonts/` is gitignored): + +```bash +git add -f examples/consumer-app/public/fonts/MyFont.woff2 +``` -**Subset font in-repo (for CI):** To commit a small, licensed subset `.woff2` so `vite build` has a real file at the path referenced in `fonts.css`, use once: `git add -f examples/consumer-app/public/fonts/MyFont.woff2` (adjust the filename to match `fonts.css`). After that, the file stays tracked like any other source file. +The `-f` flag is required once; afterward the file is tracked like any other source. The committed subset is licensed for limited testing per **LICENSE**, not production web use. ## Requirements -- Node.js 18+ +- [Node.js 18+](https://nodejs.org/en/about/releases/) (LTS) - React 18+ -- Vite 8+ +- [Vite 8+](https://vitejs.dev/) -## Related patterns +## Related Patterns -- [pattern-nextjs-webfonts](https://github.com/Monotype/pattern-nextjs-webfonts) — Next.js build-time font loading via `next/font/local` +- [pattern-nextjs-webfonts](https://github.com/Monotype/pattern-nextjs-webfonts) — Next.js `next/font/local` - [pattern-saas-fonts-embedding](https://github.com/Monotype/pattern-saas-fonts-embedding) — server-controlled font endpoints -- [pattern-cicd-fonts-usage](https://github.com/Monotype/pattern-cicd-fonts-usage) — CI/CD pipeline font management +- [pattern-cicd-fonts-usage](https://github.com/Monotype/pattern-cicd-fonts-usage) — CI/CD font scanning - [pattern-variable-fonts-usage](https://github.com/Monotype/pattern-variable-fonts-usage) — variable font axes via CSS +- [docs-webfonts-hub](https://monotype.github.io/docs-webfonts-hub/) — central developer entry point ## Support @@ -80,4 +248,4 @@ Use GitHub Discussions (Q&A category) for questions about this pattern. ## License -Sample application code in this repository is licensed under the MIT License. The subset font file in examples/consumer-app/public/fonts/ is included only as a build/CI demonstration asset and licensed for limited testing purposes only; it is not licensed for regular use on websites or redistribution. Please refer to the LICENSE file in the repository for both licenses. Canonical assertion text in [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation) remains subject to that repository’s terms. +Sample application code in this repository is licensed under the MIT License. The subset font file in `examples/consumer-app/public/fonts/` is included only as a build/CI demonstration asset and licensed for limited testing purposes only; it is not licensed for regular use on websites or redistribution. Please refer to the LICENSE file for both licenses. Canonical assertion text in [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation) remains subject to that repository's terms. From 35ec0f28d6adda6ee30f3925ecc9da3287d780f6 Mon Sep 17 00:00:00 2001 From: Jeff Carey Date: Tue, 2 Jun 2026 07:01:29 -0700 Subject: [PATCH 3/4] code --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c3c06c1..51b440f 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This README is explanatory and non-binding; authoritative assertion text lives i - The library (`src/`) uses `font-family: var(--font-family)` (see `src/MyComponent.jsx`) — no `.woff2` imports or font binaries in the published package. - Components never embed or re-export font files; the built `dist/` output contains only JavaScript and CSS that reference variables. -### How the consumer application owns font files and @font-face declarations +### How the consumer application owns font files and `@font-face` declarations - The consumer app (`examples/consumer-app/`) defines `@font-face` in `fonts.css` and places files under `public/fonts/` (served by Vite as `/fonts/...`). - `examples/consumer-app/main.jsx` imports `./fonts.css` before rendering so the browser parses `@font-face` first. @@ -48,7 +48,7 @@ A component library that bundles font files redistributes them to every applicat Use this pattern when your component library is framework-agnostic or your app does not use Next.js. Use [pattern-nextjs-webfonts](https://github.com/Monotype/pattern-nextjs-webfonts) when the app is Next.js and you want build-time font optimization. -## How to Implement @font-face in the Consumer Application +## How to Implement `@font-face` in the Consumer Application **This repository's demo** uses `examples/consumer-app/fonts.css` with `font-family: "MyFont"`, `src: url("/fonts/MyFont.woff2")`, and `:root { --font-family: "MyFont", system-ui, sans-serif; }`, with the file at `examples/consumer-app/public/fonts/MyFont.woff2`. From 635239e240819a47af9d332d64878fa89d3a2773 Mon Sep 17 00:00:00 2001 From: Jeff Carey Date: Tue, 2 Jun 2026 07:10:21 -0700 Subject: [PATCH 4/4] usually --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 51b440f..7671bcf 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ The most common cause is a missing `Access-Control-Allow-Origin` header when fon ### Do I need a different license to self-host Monotype fonts compared to using a cloud CDN service? -Yes. A **desktop** license does not permit web delivery. **Self-hosting** requires a web font license that explicitly allows serving WOFF2/WOFF from your infrastructure. **Monotype CDN** delivery is governed by separate terms (often including usage metering). Confirm your agreement covers self-hosted delivery and whether a tracking script is required alongside `@font-face`. See [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation). +Yes. A **desktop** license usually does not permit web delivery. **Self-hosting** requires a web font license that explicitly allows serving WOFF2/WOFF from your infrastructure. **Monotype CDN** delivery is governed by separate terms (often including usage metering). Confirm your agreement covers self-hosted delivery and whether a tracking script is required alongside `@font-face`. See [reference-fonts-implementation](https://github.com/Monotype/reference-fonts-implementation). ### When is a Monotype tracking script required with self-hosted fonts? @@ -168,7 +168,7 @@ Some web font licenses require a JavaScript tracking script on every page that u ### Can I use a desktop font license for web delivery in a React app? -No. Desktop licenses cover local design use only, not serving fonts to browsers via `@font-face`. A valid Monotype web font license scoped to your serving domain is required. +No. Desktop licenses usually cover local design use only, not serving fonts to browsers via `@font-face`. A valid Monotype web font license scoped to your serving domain is required. ---