Skip to content

Latest commit

 

History

History

jdfjs

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

README.md

jdf.js

npm license

Render JDF (JSON Document Format) files in any web page with a single tag. Like PDF.js — but the file you point at is plain JSON, so you can also generate it, diff it, and edit it with any tool.

<link rel="stylesheet" href="https://unpkg.com/@uurtech/jdf@0.1.11/dist/jdfjs.css">
<script type="module" src="https://unpkg.com/@uurtech/jdf@0.1.11"></script>

<jdf src="/whitepaper.jdf"></jdf>

That's the whole thing. Every <jdf> tag on the page is detected on load and rendered in place.

Install

npm install @uurtech/jdf

Or via CDN — no install at all:

<script type="module" src="https://unpkg.com/@uurtech/jdf@0.1.11"></script>

Usage

<jdf src="/doc.jdf"></jdf>

<!-- Configure with attributes -->
<jdf src="/doc.jdf"
     width="800"
     height="600"
     zoom="1.2"
     sidebar="true"
     dark-mode="auto"></jdf>

That is the only embed form. The <jdf> element is registered as a custom element with reactive attributes — change src programmatically and the embed updates:

document.querySelector("jdf").setAttribute("src", "/other.jdf");

Configuration

Attribute Type Default Notes
src string required URL to a .jdf (plain JSON) or .jdfx (zip bundle) file. The extension determines the parser.
width number (px) or any CSS length — e.g. "800" or "100%"
height number (px) or any CSS length 600px e.g. "80vh"
zoom number 1 1 = 100%
fit "manual" · "fit-width" · "fit-page" "manual" Auto-zoom mode
sidebar boolean false Show page-thumbnail sidebar
toolbar boolean true Show toolbar (zoom, page nav)
dark-mode "auto" · "light" · "dark" "auto" Follows OS by default
page integer (0-based) 0 Initial page
manual boolean — Skip auto-init for this element

Programmatic API

For full control, install via npm and call the JS API directly:

import { embed, render, JDFViewer, jdf } from "@uurtech/jdf";
import "@uurtech/jdf/style.css";

// 1. Embed by URL into any container
const v = await embed("#viewer", "/doc.jdf", {
  zoom: 1.2,
  sidebar: true,
  width: "100%",
  height: "80vh",
  fit: "fit-width",
  onPageChange: (i) => console.log("on page", i),
  onLoad: (doc) => console.log("loaded", doc.meta.title),
});
v.goToPage(2);
v.setZoom(1.5);

// Elements carry an `id` (the PDF importer writes `p<page>-e<n>`); every wrapper
// exposes it as `data-jdf-id`. Point at them:
v.scrollToElement("p3-e12", { highlight: true });          // e.g. a retrieval hit
v.highlight(["p3-e12", "p3-e13"], { color: "#22c55e" });   // ids…
v.highlight({ page: 2, x: 20, y: 80, width: 120, height: 8 }); // …or a box in mm
v.clearHighlights();
const off = v.onElementClick(({ id, type, pageIndex, path, element }) => console.log(id, type, pageIndex));
// <jdf> tag users: el.addEventListener("jdf-ready", e => e.detail.viewer…) and
// el.addEventListener("jdf-element-click", e => e.detail.id); or getViewer(el).
v.destroy();

// 2. Render an in-memory document (no fetch)
import type { JdfDocument } from "@uurtech/jdf";
const doc: JdfDocument = {
  $jdf: "1.0.0",
  meta: { title: "Generated", pageSize: "A4" },
  pages: [{
    elements: [
      { type: "text", content: "Hello", heading: 1, position: { x: 0, y: 5 }, width: 166 }
    ],
  }],
};
render("#out", doc);

// 3. Class form for advanced wiring
const el = document.getElementById("v")!;
const v3 = new JDFViewer(el, doc, { darkMode: "dark" });
v3.setDocument(otherDoc); // hot-swap

SPAs / async content

Auto-init runs on DOMContentLoaded and watches the DOM with a MutationObserver, so <jdf> tags added later are picked up automatically. To trigger a manual scan after a route change:

import { jdf } from "@uurtech/jdf";
jdf();                       // scan the whole document
jdf(myContainer);             // scan only inside myContainer

To opt out per element, add manual. To disable auto-init globally, set window.JDFjsAutoInit = false before loading the script.

Hosting .jdf and .jdfx files

Both formats are static — any static host works.

.jdf (plain JSON):

Content-Type: application/json
Cache-Control: public, max-age=3600
Access-Control-Allow-Origin: *

.jdfx (zip bundle, used when the document carries embedded images / fonts):

Content-Type: application/jdf+zip
Cache-Control: public, max-age=3600
Access-Control-Allow-Origin: *

The fetch needs CORS allowed if the file is on a different origin from your page. jdf.js detects the extension on src and parses the right format automatically — <jdf src="/whitepaper.jdfx"> just works.

Browser support

Chrome 88+, Firefox 87+, Safari 14+, Edge 88+.

Feature parity with the desktop reader

jdf.js renders every JDF element type the desktop Reader does:

  • text (with heading: 1-6, align, tocEntry, internal/external link)
  • richtext (per-run bold/italic/underline/strikethrough/color/fontSize/fontFamily/link)
  • image (embedded base64 or URL/path; fit: contain|cover|fill|none)
  • table (headers, alternating rows, configurable borders, column alignment, cell-level styles)
  • list (ordered / unordered, mixed nested)
  • shape (rect, circle, ellipse, line, SVG path; fill, stroke, opacity)
  • collapsible (expandable section)
  • toc (auto-generated, hierarchical, click-to-navigate)

Plus headers/footers (template strings or full element trees), custom page sizes, doc-level / per-page orientation, and internal #page-N link navigation.

License

MIT — see LICENSE.

By Ugur Kazdal (@uurtech).