You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+161-5Lines changed: 161 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,8 @@
1
1
# odf-kit
2
2
3
-
Createand fill OpenDocument Format files (.odt) in TypeScript/JavaScript. Build documents from scratch with a clean API, or fill existing templates with data. Works in Node.js and browsers. No LibreOffice dependency — just spec-compliant ODF files.
3
+
Create, fill, read, and convert OpenDocument Format files (.odt) in TypeScript/JavaScript. Build documents from scratch with a clean API, fill existing templates with data, read .odt files into a structured model, or export to Typst for PDF generation. Works in Node.js and browsers. No LibreOffice dependency — just spec-compliant ODF files.
4
4
5
-
**Two ways to generate documents:**
5
+
**Four ways to work with .odt files:**
6
6
7
7
```typescript
8
8
// 1. Build from scratch
@@ -40,6 +40,44 @@ const result = fillTemplate(template, {
Generated `.odt` files open in LibreOffice, Apache OpenOffice, OnlyOffice, Collabora, Google Docs, Microsoft Office, and any ODF-compliant application.
44
82
45
83
## Why odf-kit?
@@ -54,7 +92,7 @@ odf-kit fills that gap with a single runtime dependency, full TypeScript types,
54
92
npm install odf-kit
55
93
```
56
94
57
-
Works in Node.js 18+ and modern browsers. ESM only.
95
+
Works in Node.js 22+ and modern browsers. ESM only.
58
96
59
97
**Browser** — use any bundler (Vite, webpack, esbuild, Rollup):
60
98
@@ -130,6 +168,8 @@ URL.revokeObjectURL(url);
130
168
-**Links** — external hyperlinks, internal bookmark links, formatted link text
131
169
-**Bookmarks** — named anchor points for internal navigation
132
170
-**Tab stops** — left, center, right alignment with configurable positions
171
+
-**Read & convert** — parse .odt files into a structured document model; convert to HTML with `odtToHtml()`
172
+
-**Export to Typst** — convert any .odt file to Typst markup with `odtToTypst()`; compile to PDF with the Typst CLI
133
173
134
174
## Template Engine
135
175
@@ -234,6 +274,78 @@ LibreOffice often fragments user-typed text like `{name}` across multiple XML el
234
274
235
275
Template syntax follows [Mustache](https://mustache.github.io/) conventions, proven in document templating by [docxtemplater](https://docxtemplater.com/). odf-kit's engine is a clean-room implementation purpose-built for ODF.
236
276
277
+
## Reading and Converting .odt Files
278
+
279
+
Import from `odf-kit/reader` to parse existing .odt files:
if (node.kind==="heading") console.log(`h${node.level}:`, node.spans[0].text);
297
+
if (node.kind==="paragraph") console.log(node.spans.map(s=>s.text).join(""));
298
+
if (node.kind==="table") console.log(`table: ${node.rows.length} rows`);
299
+
}
300
+
```
301
+
302
+
The document model covers headings, paragraphs, tables, lists, images, footnotes, bookmarks, text fields, named sections, tracked changes, page layout, and headers/footers.
303
+
304
+
## Exporting to Typst for PDF Generation
305
+
306
+
Import from `odf-kit/typst` to convert .odt files to [Typst](https://typst.app/) markup, which can then be compiled to PDF:
Use `modelToTypst()` when you already have a parsed model — parse once, emit to multiple formats without re-reading the file:
323
+
324
+
```typescript
325
+
const model =readOdt(bytes);
326
+
const html =model.toHtml({ fragment: true }); // HTML
327
+
const typst =modelToTypst(model); // Typst markup
328
+
```
329
+
330
+
Both functions are zero-dependency pure functions — no filesystem access, no child process, no Typst installation required at import time. `odf-kit/typst` works in Node.js, browsers, Deno, and any other JavaScript environment.
331
+
332
+
**Installing the Typst CLI** (only needed to compile to PDF):
333
+
334
+
```bash
335
+
# macOS
336
+
brew install typst
337
+
338
+
# Windows
339
+
winget install --id Typst.Typst
340
+
341
+
# Linux / via npm
342
+
npm install -g typst
343
+
```
344
+
345
+
**Typst coverage:** headings, paragraphs (with text-align), bold, italic, underline, strikethrough, superscript, subscript, hyperlinks, footnotes, bookmarks as labels, text fields (page number, page count), unordered and ordered lists with nesting, tables with column widths, named sections, tracked changes (final/original/changes modes), page geometry via `#set page()`, and SpanStyle character properties (color, size, font family, highlight).
346
+
347
+
Images are emitted as comment placeholders — Typst does not support inline base64 data without filesystem access. Extract `ImageNode.data` from the model and write image files alongside the `.typ` output, then substitute the placeholders with `#image("filename")` calls.
348
+
237
349
## Quick Start — Programmatic Creation
238
350
239
351
### Simple document
@@ -468,6 +580,40 @@ function fillTemplate(templateBytes: Uint8Array, data: TemplateData): Uint8Array
ThelibraryusesonlystandardJavaScriptAPIs (`TextEncoder`, `Uint8Array`) plus [fflate](https://github.com/101arrowz/fflate) for ZIP packaging. The TypeScript build enforces this — Node-specific APIs cannot exist in the library source code, guaranteeing cross-platform compatibility.
0 commit comments