odf-kit – Generate ODF documents (.odt) in TypeScript with a clean API

I built odf-kit because there was no maintained JavaScript/TypeScript library for generating proper ODF files. ODF is the ISO standard for documents (ISO/IEC 26300), the default format for LibreOffice, and required by many governments — but if you were a JS developer who needed to generate .odt files, your only option was an abandoned library from 2021 that only supported flat XML (no tables, no images, no page layout).

odf-kit generates spec-compliant .odt files that open in LibreOffice, Google Docs, and Microsoft Office. Single runtime dependency (jszip). Full TypeScript types.

What it can do today:

  • Text with formatting (bold, italic, underline, fonts, colors, highlights)
  • Tables with borders, backgrounds, column widths, and cell merging
  • Page layout (size, margins, orientation, headers, footers, page numbers)
  • Bullet and numbered lists with nesting
  • Embedded images (PNG, JPEG, etc.)
  • Hyperlinks and bookmarks

The API tries to be obvious:

const doc = new OdtDocument();
doc.addHeading("Report", 1);
doc.addParagraph("Revenue exceeded expectations.");
doc.addTable([
  ["Division", "Revenue"],
  ["North", "$2.1M"],
  ["South", "$1.8M"],
], { border: "0.5pt solid #000000" });
const bytes = await doc.save();

npm: https://www.npmjs.com/package/odf-kit
GitHub: https://github.com/GitHubNewbie0/odf-kit

This is v0.1.0 — ODT is complete, ODS/ODP/ODG are planned. Feedback welcome.

odf-kit v0.3.0 — Template Engine

v0.3.0 adds a template engine to odf-kit. You can now create a .odt template in LibreOffice with {placeholders} in the text, then fill it with data from JavaScript:

javascript

import { fillTemplate } from "odf-kit";
import { readFileSync, writeFileSync } from "fs";

const template = readFileSync("invoice-template.odt");
const result = fillTemplate(template, {
  customer: "Acme Corp",
  items: [
    { product: "Widget", qty: 5 },
    { product: "Gadget", qty: 3 },
  ],
  showNotes: true,
  notes: "Net 30",
});
writeFileSync("invoice.odt", result);

What it supports:

  • {tag} — simple replacement
  • {#tag}...{/tag} — loops (arrays) and conditionals (truthy/falsy)
  • {object.property} — dot notation for nested data
  • Headers and footers with placeholders
  • Automatic handling of LibreOffice’s XML fragmentation of placeholder text

The engine is purpose-built for ODF — it understands <text:span> splitting and cleans up editing artifacts like <text:s/> and <text:bookmark/> inside fragmented placeholders.

Zero transitive dependencies. 222 tests. Apache 2.0.

npm · GitHub · [Changelog]