Publishing
Ship your finished document in a real app.
The card is finished. This chapter is about getting it in front of users - where to keep the JSON, how to load it at runtime, and how to make sure print and offline both work.
Where the document lives
There are three common patterns. Pick whichever fits your project shape.
Bundled with the app
For documents that ship as part of your build, import the JSON directly. Bundlers handle the parsing:
import from "./content/business-card.json";
import { } from "@joy-dom/react";
import type { Spec } from "@joy-dom/spec";
export function () {
return < ={ as Spec} />;
}Use this for static documents, examples, marketing pages.
Fetched at runtime
For documents that change without redeploying the app, fetch the JSON from an API or static file:
import { , } from "react";
import { } from "@joy-dom/react";
import { , type Spec } from "@joy-dom/spec";
export function ({ }: { : string }) {
const [, ] = <Spec | null>(null);
(() => {
()
.(() => .())
.(() => .())
.();
}, []);
if (!) return null;
return < ={} />;
}The SpecSchema.parse call hardens the boundary - if the API ever serves something malformed, you see a clear error instead of a downstream rendering crash.
Generated by a server
For per-user documents (an invoice, a receipt, a report), generate the JSON on the server and send it down with the page. Same shape as fetched, just with the document inlined in the initial HTML or hydrated state.
Validation in CI
SpecSchema is a Zod schema, so you can run it anywhere. Add a CI step that validates every JSON document in the repo:
import { } from "node:fs";
import { } from "node:fs/promises";
import { } from "@joy-dom/spec";
for await (const of ("content/**/*.json")) {
const = .((, "utf8"));
const = .();
if (!.) {
.(`${} is invalid:\n${.}`);
process.exit(1);
}
}Run it in CI. Documents stay valid forever.
The print media type works at the renderer level. Trigger print preview from the browser (⌘P or Ctrl+P) and any breakpoint with { "type": "type", "value": "print" } activates. See chapter 3 for the print breakpoint we added to the card.
PDF export
Browsers let users save print preview as PDF. That's the simplest "Joy DOM → PDF" path today.
Server-side rendering to PDF (Puppeteer, Playwright) works too - point a headless browser at the
rendered page and use page.pdf().
Other renderers
The same JSON renders in Swift and Kotlin apps. See:
The document is portable; only the integration code per platform changes.
Where next
You've now seen the whole loop: build a document, validate it, style it, make it responsive, extend it with custom components, and ship it.
For deeper reference:
- Specification - every supported property, condition, and rule, with stable section numbers.
- Recipes - real-world documents you can clone and adapt.
- Renderers - install, config, and API per renderer.