
Turbodocx Html To Docx
- 29 installs
- 3 repo stars
- Updated August 4, 2026
- turbodocx/quickstart
Helps with ai & agent building tasks.
About
turbodocx-html-to-docx is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- turbodocx-html-to-docx
- AI & Agent Building
- AI-coding skill
Turbodocx Html To Docx by the numbers
- 29 all-time installs (skills.sh)
- +5 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #9,369 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/turbodocx/quickstart --skill turbodocx-html-to-docxAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 29 |
|---|---|
| repo stars | ★ 3 |
| Last updated | August 4, 2026 |
| Repository | turbodocx/quickstart ↗ |
What it does
Helps with ai & agent building tasks.
Files
HTML to DOCX Setup
This skill adds @turbodocx/html-to-docx to a JavaScript/TypeScript project — a zero-dependency library that converts HTML strings to Word documents without Puppeteer, Chrome, or LibreOffice. It runs in Node.js and in the browser (via the bundled IIFE/ESM builds).
Prefer server-side when possible. Running this server-side is faster, avoids the ~2.4 MB browser bundle, sidesteps polyfill requirements, and keeps sharp (for SVG → PNG conversion) available. Default to a server-side integration whenever the project has any backend (Express/Fastify/Next.js API route/etc.) and only fall back to the browser bundle when the project is genuinely static or the user explicitly asks for client-side generation.Phase 1: Detect the Project Type
Use Glob to check what kind of project this is:
1. Node.js / npm-based project — package.json exists in the root. This is the preferred path.
- Also check for
tsconfig.jsonto determine if TypeScript is in use. - Detect the package manager from lockfiles:
pnpm-lock.yaml→ pnpmyarn.lock→ yarnbun.lockb→ bunpackage-lock.jsonor none → npm- Check
package.jsonfor"type": "module"to determine ESM vs CommonJS imports. - If the project has both a server runtime and a client (e.g., Next.js, Remix, Nuxt, SvelteKit), default to the server route/handler/action path — do not put document generation in a client component unless the user explicitly asks.
- Proceed to Phase 2 (npm install path).
2. Browser-only project — no package.json, but HTML files exist (*.html) or the user has explicitly said they want to use this in a static page / CDN setup. Before committing to this path, briefly confirm with the user that they don't have a backend they'd rather run this in — server-side is preferred. If they confirm browser is required:
- Skip npm install entirely. The library ships a self-contained browser bundle (
dist/html-to-docx.browser.js, ~2.4 MB IIFE) with all dependencies inlined. - Read the Browser Usage section in
references/usage.mdfor the polyfill snippet, theHTMLToDOCX(...)global, and the limitations (nosharp, CORS-restricted remote images, no filesystem). - Drop in a
<script src="...">referencing either a hosted copy or a CDN build, and generate a minimal working example tailored to the user's page. - Skip Phases 2-4 below; the browser path is install-less.
3. Neither — no package.json and no HTML files. Ask the user which environment they're targeting (Node.js, bundler, or static HTML) before proceeding, and recommend server-side as the default.
Phase 2: Install the Package
Run the install command for the detected package manager:
- npm:
npm install @turbodocx/html-to-docx - pnpm:
pnpm add @turbodocx/html-to-docx - yarn:
yarn add @turbodocx/html-to-docx - bun:
bun add @turbodocx/html-to-docx
No environment variables are needed — this is a local library with no API keys.
Phase 3: Read Reference
Read references/usage.md from this skill's directory. It contains the full API surface, configuration options, and code examples.
Phase 4: Analyze Codebase and Generate Code
Step 4.1: Explore the project
Use Glob and Read to understand:
- Where source files live (
src/,app/,lib/, root) - What framework is in use (Express, Fastify, NestJS, Next.js, Hono, Koa, or none)
- Existing patterns: how routes are defined, how files are organized, naming conventions
- Whether the project uses TypeScript or JavaScript
- ESM (
import) or CommonJS (require) style
Step 4.2: Confirm with the user
Briefly share what you found and where you plan to put the new files. Ask if this looks right.
Step 4.3: Generate the helper module
Create a helper module that wraps HTMLtoDOCX with sensible defaults. Place it where the project keeps its utilities (e.g., src/lib/, src/utils/, lib/).
The helper should:
- Import
HTMLtoDOCXusing the project's import style (ESM or CJS) - Export a function like
generateDocx(html, options?)that callsHTMLtoDOCXand returns aBuffer - Include commonly useful defaults (font, margins) that the user can override
- Use TypeScript if the project uses TypeScript
Step 4.4: Generate integration code
Based on what the project needs:
If it's a web server (Express, Fastify, NestJS, Next.js, etc.): Create an endpoint that accepts HTML (in the request body) and returns a .docx file. Match the framework's routing pattern:
- Express:
Routerwithres.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')andres.send(buffer) - Next.js App Router:
app/api/.../route.tsexportingPOSTfunction, returnnew Response(buffer, { headers }) - NestJS:
@Controller+@Postwith@Res() resfor streaming the buffer - Other frameworks: match their conventions
Set the response headers:
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
Content-Disposition: attachment; filename="document.docx"Wire the route into the app's main file (unless file-based routing like Next.js).
If it's a standalone/script project: Create a script that reads HTML (from a file, stdin, or a string) and writes a .docx file. Include a basic example HTML string to demonstrate.
Phase 5: Verify and Summarize
If the project uses TypeScript, run npx tsc --noEmit to check for type errors.
Print a summary:
- Files created and modified
- Package installed
- How to use (example curl command for endpoints, or how to run the script)
- Link to docs: https://docs.turbodocx.com/docs
- Key options they can customize (page size, orientation, margins, fonts, headers/footers)
@turbodocx/html-to-docx — API Reference
Install
npm install @turbodocx/html-to-docx
# Optional for SVG image support:
npm install @turbodocx/html-to-docx sharpImport
// ESM / TypeScript
import HTMLtoDOCX from '@turbodocx/html-to-docx';
// CommonJS
const HTMLtoDOCX = require('@turbodocx/html-to-docx');Function Signature
async function HTMLtoDOCX(
htmlString: string, // Required: HTML content to convert
headerHTMLString?: string | null, // Optional: HTML for page header
documentOptions?: DocumentOptions, // Optional: configuration
footerHTMLString?: string | null // Optional: HTML for page footer
): Promise<Buffer | ArrayBuffer | Blob>Returns Buffer in Node.js, Blob in browsers. Both can be persisted or streamed — see Browser Usage section for the browser path.
Basic Usage
import HTMLtoDOCX from '@turbodocx/html-to-docx';
import { writeFileSync } from 'fs';
const html = `
<h1>Quarterly Report</h1>
<p>Generated on ${new Date().toLocaleDateString()}</p>
<table>
<tr><th>Metric</th><th>Value</th></tr>
<tr><td>Revenue</td><td>$1.2M</td></tr>
</table>
`;
const buffer = await HTMLtoDOCX(html);
writeFileSync('report.docx', buffer);Express Endpoint Example
import { Router, Request, Response } from 'express';
import HTMLtoDOCX from '@turbodocx/html-to-docx';
const router = Router();
router.post('/generate', async (req: Request, res: Response) => {
try {
const { html, filename = 'document', options } = req.body;
if (!html) {
return res.status(400).json({ error: 'html field is required' });
}
const buffer = await HTMLtoDOCX(html, null, options);
res.setHeader(
'Content-Type',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
);
res.setHeader(
'Content-Disposition',
`attachment; filename="${filename}.docx"`
);
res.send(buffer);
} catch (error) {
res.status(500).json({ error: 'Document generation failed' });
}
});
export default router;Configuration Options
Page Layout
const options = {
orientation: 'portrait', // 'portrait' | 'landscape'
pageSize: {
width: 12240, // Letter width in TWIP (1/20th of a point)
height: 15840, // Letter height
},
margins: {
top: 1440, // 1 inch (1440 TWIP = 1 inch)
right: 1800,
bottom: 1440,
left: 1800,
header: 720,
footer: 720,
gutter: 0, // binding gutter (added to inner margin for double-sided printing)
},
};Common page sizes in TWIP:
- Letter: 12240 x 15840
- A4: 11906 x 16838
- Legal: 12240 x 20160
Typography
const options = {
font: 'Arial', // Default: 'Times New Roman'
fontSize: 24, // In half-points (24 = 12pt). Default: 22 (11pt)
};Heading Styles
All heading styles are nested under the heading key. Each level supports font, fontSize, bold, spacing, keepLines, keepNext, and outlineLevel.
const options = {
heading: {
heading1: {
font: 'Arial',
fontSize: 32, // 16pt
bold: true,
spacing: { before: 240, after: 120 },
keepLines: true, // keep all lines on same page
keepNext: true, // keep with the following paragraph
},
heading2: {
font: 'Arial',
fontSize: 28, // 14pt
bold: true,
spacing: { before: 200, after: 100 },
},
heading3: { font: 'Arial', fontSize: 24, bold: true },
heading4: { font: 'Arial', fontSize: 22, bold: true },
heading5: { font: 'Arial', fontSize: 20, bold: false },
heading6: { font: 'Arial', fontSize: 18, bold: false },
},
};Headers and Footers
const headerHtml = '<p style="text-align: center">Company Name</p>';
const footerHtml = '<p style="text-align: center">Confidential</p>';
const options = {
header: true,
headerType: 'default', // 'default' | 'first' | 'even'
footer: true,
footerType: 'default', // 'default' | 'first' | 'even'
pageNumber: true, // Adds page numbers to footer
skipFirstHeaderFooter: true, // omit header/footer on first page
};
const buffer = await HTMLtoDOCX(html, headerHtml, options, footerHtml);Line Numbers
const options = {
lineNumber: true,
lineNumberOptions: {
start: 1,
countBy: 1,
restart: 'newPage', // 'continuous' | 'newPage' | 'newSection'
},
};List Numbering
const options = {
numbering: {
defaultOrderedListStyleType: 'decimal', // controls <ol> list style
},
};Document Metadata
const options = {
title: 'Quarterly Report',
subject: 'Q4 2025 Financial Summary',
creator: 'Report Generator',
keywords: ['finance', 'quarterly'],
description: 'Auto-generated financial report',
lastModifiedBy: 'Report Generator',
revision: 1,
createdAt: new Date(),
modifiedAt: new Date(),
};Table Options
const options = {
table: {
row: { cantSplit: true },
borderOptions: { size: 1, color: '000000' },
},
};Image Processing
const options = {
imageProcessing: {
maxRetries: 2,
downloadTimeout: 5000, // ms before giving up on a remote image
maxImageSize: 10485760, // 10MB — skip images larger than this
svgHandling: 'convert', // 'convert' (needs sharp) | 'native' (Office 2019+) | 'auto' (convert if sharp available, else native)
},
preprocessing: {
skipHTMLMinify: false, // set true if minification breaks your HTML
},
};RTL / Complex Script Languages
const options = {
direction: 'rtl',
lang: 'ar-SA',
complexScriptFontSize: 24, // font size for Arabic, Hebrew, CJK scripts (half-points)
decodeUnicode: true, // decode HTML entities in the source HTML
};Supported HTML Elements
Structure: h1-h6, p, div, span, br, hr Formatting: strong/b, em/i, u, sub, sup, pre Tables: table, thead, tbody, tr, td, th (with borders and styling) Lists: ul, ol, li (decimal, upper/lower alpha, upper/lower roman) Media: a (hyperlinks), img (base64, remote URLs, SVG) Page breaks: <div class="page-break"></div> or style="page-break-after: always"
Gotchas
- Async function — always
awaitthe result - No API keys needed — this is a purely local library
- SVG images — install
sharpfor maximum compatibility (converts SVG to PNG for Word 2007+). Without sharp, SVGs use native embedding (Office 2019+ only). UsesvgHandling: 'auto'to pick automatically. - TWIP units — page sizes and margins use TWIP (1 inch = 1440 TWIP, 1 cm = 567 TWIP)
- Image URLs — remote images are downloaded automatically; for CORS-restricted images, use base64 data URIs
- TypeScript — full type definitions included in the package
- Return type varies by runtime — Node.js returns
Buffer, browsers returnBlob. Both can be persisted, streamed, or uploaded directly. - Heading styles — all heading levels are nested under the
headingkey:{ heading: { heading1: {...}, heading2: {...} } }— not at the top level of options. - HTML minification — the library minifies your HTML before processing; if this breaks layout, set
preprocessing: { skipHTMLMinify: true }. - `null` vs `undefined` — pass
nullexplicitly for headerHTMLString/footerHTMLString when you want to skip them and still pass options as the third argument.
Full API reference: https://docs.turbodocx.com/docs
Browser Usage
Prefer server-side if possible. Server-side generation is faster, has no ~2.4 MB bundle, requires no polyfills, and keeps sharp available for SVG → PNG conversion. Only use the browser path if the project is truly static or the user has explicitly asked for client-side generation.This library runs in browsers via the bundled standalone build. It is not server-side only. There are three distribution files produced by npm run build:
| File | Format | Size | Use case |
|---|---|---|---|
dist/html-to-docx.esm.js | ES Module | ~1.6 MB | Modern bundlers (Webpack, Vite, Rollup) — deps external |
dist/html-to-docx.umd.js | UMD | ~1.6 MB | Node.js, AMD, manual dep management |
dist/html-to-docx.browser.js | IIFE | ~2.4 MB | Direct <script> / CDN — all deps bundled |
package.json already wires these up as main / module / browser, so bundlers pick the right one automatically.
Path 1 — Bundler (Vite, Webpack, Rollup, Next.js client component, etc.)
Install normally and import. The bundler picks the ESM build:
import HTMLtoDOCX from '@turbodocx/html-to-docx';
async function downloadDocx(html: string) {
const result = await HTMLtoDOCX(html);
// In browser: result is a Blob. In Node: Buffer/ArrayBuffer.
const blob = result instanceof Blob
? result
: new Blob([result], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.docx';
a.click();
URL.revokeObjectURL(url);
}Path 2 — Static HTML page (no bundler, <script> tag)
Use the IIFE bundle. Polyfills for `global`, `process`, and `Buffer` must be set before the script loads — some dependencies check for them synchronously during init:
<!DOCTYPE html>
<html>
<head><title>HTML to DOCX</title></head>
<body>
<script>
if (typeof global === 'undefined') window.global = window;
if (typeof process === 'undefined') window.process = { env: {} };
if (typeof Buffer === 'undefined') {
window.Buffer = {
from: function (data, encoding) {
if (typeof data === 'string') {
if (encoding === 'base64') {
var binary = atob(data);
var bytes = new Uint8Array(binary.length);
for (var i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
return bytes;
}
return new TextEncoder().encode(data);
}
return new Uint8Array(data);
},
isBuffer: function () { return false; }
};
}
</script>
<script src="path/to/html-to-docx.browser.js"></script>
<script>
async function generateDocument() {
// Note: the IIFE bundle exposes a global named HTMLToDOCX (capitalized).
const result = await HTMLToDOCX('<h1>Hello</h1><p>From the browser.</p>', null, {
title: 'My Document',
creator: 'Browser App'
});
const blob = result instanceof Blob
? result
: new Blob([result], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.docx';
a.click();
URL.revokeObjectURL(url);
}
</script>
<button onclick="generateDocument()">Generate DOCX</button>
</body>
</html>Building the browser bundle from source
The browser bundle ships in the npm package's dist/ directory, so most users don't need to build it. If you're working from a cloned repo or want a custom build:
npm run build # all three outputs (ESM + UMD + Browser)
npm run build:browser # browser IIFE only (dev)
npm run build:browser:prod # browser IIFE only (minified, production)Browser limitations
- `sharp` not available — SVG images embed natively (requires Office 2019+). For broader compatibility, pre-convert SVGs to PNG before passing to the library.
- CORS — Remote
<img src="https://...">URLs must be CORS-enabled, or use base64 data URIs. - No filesystem — Output is returned as
Blob/ArrayBuffer. Trigger a download viaURL.createObjectURLor upload directly.