Archive for April, 2026

Announcing OpenXmlSdkTs — The Open XML SDK for TypeScript

If you work with Office documents programmatically, you probably know the .NET Open-Xml-Sdk. It’s been the gold standard for reading, writing, and manipulating .docx, .xlsx, and .pptx files at the XML level. But if you’re working in TypeScript or JavaScript — building Office add-ins, server-side document processing in Node.js, or browser-based document tools — you’ve been on your own.

OpenXmlSdkTs brings the same programming model to TypeScript.

Why Build This?

For anyone building Word, Excel, or PowerPoint JavaScript/TypeScript add-ins, direct Open XML manipulation is often the most reliable approach. But the JavaScript ecosystem has lacked a library that provides the kind of structured, typed access to Open XML packages that .NET developers are accustomed to.

I built OpenXmlSdkTs to solve this problem. It provides the same class hierarchy, the same part navigation model, and the same LINQ to XML querying that makes the .NET SDK so productive — all in TypeScript, running in Node.js or the browser.

Note that when programming with the Open-Xml-Sdk in dotnet, I invariably use LINQ to XML, not the various classes (Paragraph, Body, etc.) that represent the markup in the Open-Xml-Sdk. I don’t care for those classes, and instead prefer to use LINQ to XML for working with the markup. Maybe one day I will detail everything that I find wrong with those classes, but that is not the purpose of this post. In any case, this TypeScript library includes only the functionality for working with markup using LINQ to XML (LtXmlTs in this case).

What You Get

Full document format support. Work with Word (.docx), Excel (.xlsx), and PowerPoint (.pptx) files.

OpenXmlPackage
├── WmlPackage        Word documents
├── SmlPackage        Excel spreadsheets
└── PmlPackage        PowerPoint presentations

OpenXmlPart
├── WmlPart           Word parts (document, styles, headers, footers, etc.)
├── SmlPart           Excel parts (workbook, worksheets, charts, etc.)
└── PmlPart           PowerPoint parts (presentation, slides, masters, etc.)

Three I/O modes. Open and save documents as binary blobs (the standard ZIP-based format), Flat OPC XML strings (required for Office JavaScript/TypeScript add-ins), or Base64 strings. The open() method auto-detects the format.

Pre-initialized namespace and element names. Static classes like W, S, P, and A provide pre-initialized XName and XNamespace objects for every element and attribute in the Open XML specification. Because these objects are atomized — two objects with the same namespace and local name are the same object — equality checks use identity comparison (===), giving excellent query performance. No more copy-pasting long namespace URIs.

Built on LINQ to XML for TypeScript. OpenXmlSdkTs is powered by ltxmlts, my TypeScript port of .NET’s LINQ to XML (which I wrote about in a previous post). You get the full API — elements(), descendants(), attributes(), functional construction — all the things that make XML manipulation so much more pleasant than working with DOMDocument.

What the Code Looks Like

Here’s a concrete example. This loads a Word document, navigates to the comments part to read comment data, adds a new bold paragraph, and saves the result:

import { WmlPackage, W, XElement } from "openxmlsdkts";
import * as fs from "fs";

const buffer = fs.readFileSync("MyDocument.docx");
const doc = await WmlPackage.open(new Blob([buffer]));

// Navigate to the main document part and get its XML
const mainPart = await doc.mainDocumentPart();
const xDoc = await mainPart!.getXDocument();

// Access comments using typed navigation
const commentsPart = await mainPart!.wordprocessingCommentsPart();
if (commentsPart) {
  const commentsXDoc = await commentsPart.getXDocument();
  for (const comment of commentsXDoc.root!.elements(W.comment)) {
    const author = comment.attribute(W.author)?.value ?? "(unknown)";
    const text = Array.from(comment.descendants(W.t))
      .map(t => t.value).join("");
    console.log(`Comment by ${author}: "${text}"`);
  }
}

// Add a bold paragraph using functional construction
const body = xDoc.root!.element(W.body);
const sectPr = body!.element(W.sectPr);
sectPr!.addBeforeSelf(
  new XElement(W.p,
    new XElement(W.r,
      new XElement(W.rPr, new XElement(W.b)),
      new XElement(W.t, "Added by OpenXmlSdkTs.")
    )
  )
);

// Save changes back
mainPart!.putXDocument(xDoc);
const savedBlob = await doc.saveToBlobAsync();
fs.writeFileSync("Modified.docx", Buffer.from(await savedBlob.arrayBuffer()));

If you’ve used the .NET Open XML SDK, this should feel immediately familiar. The pre-atomized names (W.p, W.r, W.t, W.b) are the same element names you already know, and the nesting hierarchy in the functional construction mirrors the XML being produced.

Office Add-ins: First-Class Support

One of the key motivations for this library is building Office JavaScript/TypeScript add-ins. For anyone targeting macOS or Office on the web, JavaScript add-ins are the only option. And if you need to manipulate the document at the Open XML level, you need to work with Flat OPC — a single-file XML representation of the entire package.

Lightweight and Focused

The library has three runtime dependencies: jszip for ZIP compression and ltxmlts for LINQ to XML, and sax. It works in Node.js 18+ and modern browsers.

How Claude Helped

Like ltxmlts, I built OpenXmlSdkTs using Claude Code as my primary development tool. The approach was the same: targeted, methodical prompts — one class, one area of functionality at a time — with unit tests written and reviewed at each step. Claude handled the heavy lifting of translating patterns I knew from the .NET side into idiomatic TypeScript. But every design decision, every API surface choice, and every test case came from my experience with working with Open XML. This was intense, focused engineering using Claude as a powerful tool, not a magic wand.

MIT Licensed

OpenXmlSdkTs is released under the MIT License — the same license used by the C#/.NET Open-Xml-Sdk. Free for commercial and open-source use.

Get Started

Install from npm:

npm install openxmlsdkts

Both openxmlsdkts and its companion library ltxmlts are available on npmjs.

Full documentation is available in the GitHub repository, including an overview, per-class API reference docs, and runnable examples covering binary, Flat OPC, and Base64 round-tripping.

If you’re building Office add-ins, processing documents on the server, or doing anything with Open XML in TypeScript — give it a try.

Comments