doclang — generate Microsoft Word documents from JavaScript.
DocLang is a TypeScript library that builds professional .docx files from semantic components. Describe the structure of a resume — or any document — and DocLang handles typography, spacing, and layout. The output opens in Word, Google Docs, and LibreOffice.
- languageTypeScript — ESM plus a browser bundle
- outputstandard .docx, no HTML or PDF hacks
- peer depdocx, used for packing
- licenseMIT
npm install doclang docx
pnpm add doclang docx
docx is a peer dependency used to pack the final document.
CDN
Import DocLang without a build step. The browser bundle exposes everything on the global DocLang, with Packer on DocLang.docx.
<!-- index.html --> <script src="https://unpkg.com/doclang/dist/doclang.min.js"></script> <script> const { Resume, Header, Name } = DocLang; const { Packer } = DocLang.docx; </script>
See README.md for the full CDN setup guide.
Compose a document from components, then hand it to exportFile(). Page margins default to 0.8in top/bottom and 1in left/right.
import { Resume, Header, Name, Designation, Contact, Summary, Experience, ExperienceItem, Skills, Skill, Education, EducationItem, exportFile, } from "doclang"; const resume = Resume( Header( Name("Jane Smith"), Designation("Software Engineer"), Contact({ email: "jane@example.com", phone: "+1 555 123 4567", github: "github.com/janesmith", }) ), Summary("Full-stack engineer with 8+ years of experience."), Experience( ExperienceItem({ company: "Tech Corp", designation: "Senior Engineer", duration: "2021 – Present", points: [ "Led microservices migration", "Reduced deploy time by 70%", ], }) ), Skills( Skill("TypeScript"), Skill("Node.js") ) ); await exportFile(resume, { fileName: "jane_smith", pdf: true, });
Run it and a jane_smith.docx (plus .pdf when requested) lands in ./exports.
Every component returns a SectionComponent — a function that produces paragraphs for the document body. Pass any component or a raw string into Resume() or a container. All accept an optional ResumeStyles override as the last argument.
generic
| name | signature | purpose |
|---|---|---|
| Heading | Heading(text, styles?) | Large heading paragraph. |
| SubHeading | SubHeading(text, styles?) | Sub-section title. |
| SectionHeading | SectionHeading(text, styles?) | Accent-colored section heading, used by containers. |
| Text | Text(text, styles?) | Normal paragraph. |
| SmallText | SmallText(text, styles?) | Secondary small text. |
| Bullet | Bullet(text, styles?) | Single bullet point. |
| BulletList | BulletList(items, styles?) | List of bullet points. |
| Divider | Divider() | Horizontal rule. |
| Spacer | Spacer(points?) | Vertical spacing, default 100 twips. |
header
| name | signature | purpose |
|---|---|---|
| Header | Header(...children) | Container for name, title, and contact info. |
| Name | Name(name, styles?) | The candidate's name, large and centered. |
| Designation | Designation(title, styles?) | Professional title below the name. |
| Contact | Contact(info, styles?) | Email, phone, links — pipe separated on one line. |
| Address | Address(address, styles?) | Address line in small text. |
| Photo | Photo(config) | Inline photo image from buffer data. |
| PhotoPath | PhotoPath(path, config) | Photo from a local file path — Node only. |
profile
| name | signature | purpose |
|---|---|---|
| Summary | Summary(text, styles?) | Professional summary paragraph. |
| Objective | Objective(text, styles?) | Career objective paragraph. |
experience
| name | signature | purpose |
|---|---|---|
| Experience | Experience(...items) | Container that renders an "Experience" heading. |
| ExperienceItem | ExperienceItem(config, styles?) | Company + duration, designation, bullet points. |
| Company | Company(name, styles?) | Company name for custom layouts. |
| Duration | Duration(text, styles?) | Duration for custom layouts. |
education
| name | signature | purpose |
|---|---|---|
| Education | Education(...items) | Container that renders an "Education" heading. |
| EducationItem | EducationItem(config, styles?) | Institution + year, degree below. |
| Institution | Institution(name, styles?) | Institution name for custom layouts. |
| Degree | Degree(name, styles?) | Degree for custom layouts. |
skills
| name | signature | purpose |
|---|---|---|
| Skills | Skills(...skills) | Container that renders a "Skills" heading. |
| Skill | Skill(name, styles?) | Single skill as a bullet point. |
projects
| name | signature | purpose |
|---|---|---|
| Projects | Projects(...items) | Container that renders a "Projects" heading. |
| Project | Project(config, styles?) | Name, optional description, points, and link. |
certifications
| name | signature | purpose |
|---|---|---|
| Certifications | Certifications(...items) | Container that renders a "Certifications" heading. |
| Certification | Certification(config, styles?) | Name, optional issuer, and date. |
languages
| name | signature | purpose |
|---|---|---|
| Languages | Languages(...items) | Container that renders a "Languages" heading. |
| Language | Language(config, styles?) | Name, optional proficiency. |
awards
| name | signature | purpose |
|---|---|---|
| Awards | Awards(...items) | Container that renders an "Awards" heading. |
| Award | Award(config, styles?) | Title, optional issuer, and date. |
references
| name | signature | purpose |
|---|---|---|
| References | References(...items) | Container that renders a "References" heading. |
| Reference | Reference(config, styles?) | Name, "title at company", email | phone. |
defaultStyles ships a built-in design. createStyles(overrides?) merges a partial override over it — pass any subset of tokens, leave the rest to the defaults. Sizes are in half-points (24 = 12pt), colors are hex without the #, and spacing is in twips.
import { createStyles, Resume, Header, Name, Experience, ExperienceItem } from "doclang"; const styles = createStyles({ name: { font: "Georgia", size: 36, bold: true, color: "1A1A2E" }, sectionHeading: { color: "E94560", bold: true }, text: { font: "Calibri", size: 20 }, }); const resume = Resume( Header(Name("John Doe", styles)), Experience( ExperienceItem({ company: "Tech Corp", designation: "Engineer", duration: "2020 – Present", points: ["Built things"], }, styles) ) );
Style tokens
| token | used by |
|---|---|
| heading | Heading |
| subHeading | SubHeading |
| sectionHeading | SectionHeading and all section containers |
| name | Name |
| designation | Designation, ExperienceItem, EducationItem |
| text | Text, Summary, Objective |
| smallText | SmallText, Address |
| bullet | Bullet, BulletList |
| company | Company, Institution, Skill, Project, Certification, Language, Award |
| duration | Duration, and experience / education / certification / award dates |
| contact | Contact |
| skill | Skill |
Each token is a StyleToken with optional font, size, bold, italics, uppercase, color, spacing, alignment, and border fields.
exportFile(document, options?)
The recommended way to save a document. Handles DOCX generation, file writing, and optional PDF conversion — no need to import Packer, fs, or child_process.
| option | type | default | purpose |
|---|---|---|---|
| outputDir | string | "./exports" | Directory to save files in, created automatically. |
| fileName | string | "resume" | Base file name without extension. |
| boolean | false | Convert DOCX to PDF with LibreOffice. |
Returns { docx: string, pdf?: string } with absolute paths. Throws meaningful errors if any step fails. PDF conversion requires LibreOffice (soffice) on PATH.
const { docx } = await exportFile(resume, { outputDir: "./exports", fileName: "john_doe", }); const { docx, pdf } = await exportFile(resume, { outputDir: "./exports", fileName: "john_doe", pdf: true, // requires soffice });
Utilities
| name | signature | purpose |
|---|---|---|
| formatContact | formatContact(info): string | Formats a ContactInfo object into a pipe-separated string. |
| normalizeList | normalizeList(items): string[] | Filters out undefined, null, and empty entries. |
| sectionId | sectionId(label): string | Creates a section separator name, e.g. "section_experience". |
Types
Configuration objects — ContactInfo, PhotoConfig, ExperienceItemConfig, EducationItemConfig, ProjectConfig, CertificationConfig, LanguageConfig, AwardConfig, ReferenceConfig — mirror the component signatures above. The core types:
type SectionComponent = () => Paragraph[]; interface StyleToken { font?: string; size?: number; // half-points, 24 = 12pt bold?: boolean; italics?: boolean; uppercase?: boolean; color?: string; // hex, no "#" spacing?: { before?: number; after?: number; line?: number }; alignment?: "left" | "center" | "right"; }
Full signatures for every config object live in REFERENCE.md.