Skip to content

Builder API ​

The DocxBuilder class, createDocx() factory, renderDocx() JSON entry point, and export methods.

createDocx(config?) ​

The primary entry point. Returns a fluent DocxBuilder for chaining content.

ts
import { createDocx } from 'docx-kit'

const doc = createDocx({
  page: { size: 'A4', margin: '2cm 2.5cm' },
  styles: { /* defineStyles(...) */ },
  theme: { /* theme tokens */ },
  defaults: {
    text: { fontFamily: 'Arial', fontSize: 11 },
  },
  metadata: {
    title: 'Annual Report',
    creator: 'Alice',
    customProperties: {
      Department: 'Finance',
    },
  },
})

Binary font data can be embedded once and referenced by its family name in document styles:

ts
import { readFile } from 'node:fs/promises'
import { createDocx } from 'docx-kit/node'

const doc = createDocx({
  fonts: [
    {
      name: 'Inter',
      data: await readFile('./Inter-Regular.ttf'),
    },
  ],
  defaults: {
    text: { fontFamily: 'Inter' },
  },
})

DocxBuilder<TStyles, TPlugins> ​

The fluent builder class returned by createDocx().

ts
class DocxBuilder<
  TStyles extends StyleSheet = StyleSheet,
  TPlugins extends PluginRegistry = PluginRegistry,
> {
  // ── Content ──
  h1(text: string, opts?: StyleOptions): this
  h2(text: string, opts?: StyleOptions): this
  h3(text: string, opts?: StyleOptions): this
  h4(text: string, opts?: StyleOptions): this
  h5(text: string, opts?: StyleOptions): this
  h6(text: string, opts?: StyleOptions): this
  p(text: string | InlineNode[], opts?: StyleOptions): this
  bookmark(name: string, children: (string | TextNode)[], opts?: StyleOptions): this
  bulletList(items: BulletItem[], opts?: StyleOptions): this
  checkbox(options?: CheckboxOptions): this
  comment(options: CommentOptions): this
  footnote(content: (string | ParagraphNode)[], opts?: StyleOptions): this
  math(children: MathExpression[]): this
  numberedList(items: BulletItem[], opts?: StyleOptions): this
  hyperlink(url: string, text: string, opts?: StyleOptions): this
  internalLink(anchor: string, text: string, opts?: StyleOptions): this
  insertedText(options: RevisionOptions): this
  deletedText(options: RevisionOptions): this
  image(options: ImageNode): this
  table<T>(options: TableOptions<T>): this
  textBox(options: TextBoxOptions): this
  thematicBreak(opts?: StyleOptions): this
  columnBreak(): this
  pageBreak(): this
  section(config?: SectionConfig): this
  add(node: BlockNode): this

  // ── Plugins ──
  use(plugin: DocxPlugin): DocxBuilder<TStyles, TPlugins & Record<TName, TOptions>>
  plugin(name: TName, options: TOptions, opts?: StyleOptions): this

  // ── Rich Content ──
  span(text: string, style?: DocxStyleRule): TextNode
  inlineImg(options: InlineImageOptions): ImageNode

  // ── Debug ──
  toJSON(): object

  // ── Export ──
  save(filename: string): Promise<void>       // Node.js only
  toBlob(): Promise<Blob>
  toUint8Array(): Promise<Uint8Array>
  toBuffer(): Promise<Uint8Array>              // alias for toUint8Array
  toBase64(): Promise<string>
  toDocument(): Promise<Document>              // raw docx Document
}

Content Methods ​

MethodDescription
.h1(text, opts?)Level-1 heading
.h2(text, opts?)Level-2 heading
.h3(text, opts?)Level-3 heading
.h4(text, opts?)Level-4 heading
.h5(text, opts?)Level-5 heading
.h6(text, opts?)Level-6 heading
.p(text, opts?)Paragraph with optional inline children
.bookmark(name, children, opts?)Named bookmark target
.bulletList(items, opts?)Unordered list
.checkbox(options?)Word checkbox content control
.comment(options)Annotated range with a Word comment
.footnote(content, opts?)Footnote reference and body
.math(children)Structured Office Math expression
.numberedList(items, opts?)Ordered list
.hyperlink(url, text, opts?)Clickable hyperlink
.internalLink(anchor, text, opts?)Link to a bookmark in the document
.insertedText(options)Tracked insertion
.deletedText(options)Tracked deletion
.table({ columns, data, ... })Data table
.image({ data, width?, height?, ... })Embedded image
.textBox(options)Positioned Word text box
.thematicBreak(opts?)Horizontal thematic break
.columnBreak()Forced break to the next section column
.pageBreak()Forced page break
.section(config?)Start a new section
.plugin(name, options, opts?)Invoke registered plugin
.use(plugin)Register a plugin
.add(node)Add raw DSL node

span() and inlineImg() Helpers ​

These create inline content nodes for use inside .p():

ts
import { span, inlineImg } from 'docx-kit'

// span: creates a TextNode
doc.p([
  span('Hello '),
  span('world', { bold: true, color: '#e11d48' }),
  span('!'),
])

// inlineImg: creates an inline ImageNode
doc.p([
  span('Icon: '),
  inlineImg({ data: iconDataUrl, width: 16, height: 16 }),
  span(' done!'),
])

Table Options ​

ts
interface TableOptions<TData> {
  columns: {
    key: string
    title: string
    align?: 'left' | 'center' | 'right'
    width?: UnitValue
    cellStyle?: DocxStyleRule | TableCellStyleResolver<TData>
    headerCellStyle?: DocxStyleRule
    render?: (value: unknown, row: TData, index: number) => string | InlineNode[]
  }[]
  data: TData[]
  alignment?: 'left' | 'center' | 'right'
  bordered?: boolean
  borders?: TableBordersConfig
  floating?: TableFloatingOptions
  striped?: boolean
  header?: boolean
  layout?: 'autofit' | 'fixed'
  styleName?: string
  tableLook?: TableLookOptions
  visuallyRightToLeft?: boolean
  width?: UnitValue
  headerCellStyle?: DocxStyleRule
  cellStyle?: DocxStyleRule | TableCellStyleResolver<TData>
}

Floating positioning supports side-by-side tables by anchoring two fixed-width tables at different horizontal offsets:

ts
doc
  .table({
    columns,
    data: leftData,
    layout: 'fixed',
    width: '45%',
    floating: { horizontalAnchor: 'page', x: '0.5in', y: '2in' },
  })
  .table({
    columns,
    data: rightData,
    layout: 'fixed',
    width: '45%',
    floating: { horizontalAnchor: 'page', x: '4.25in', y: '2in' },
  })

Export Methods ​

ts
import { createDocx } from 'docx-kit/node'

const doc = createDocx()

await doc.toBlob()         // → Blob (browser & Node.js)
await doc.toUint8Array()   // → Uint8Array
await doc.toBuffer()       // → Uint8Array (alias)
await doc.toBase64()       // → base64 string
await doc.toStream()       // → Node.js stream (Node.js only)
await doc.save('f.docx')   // → writes to disk (Node.js only)
await doc.toDocument()     // → raw docx Document
doc.toJSON()               // → shallow config/content view (inspection)

toJSON() returns a shallow view of the config and content, not a lossless persistence format. It does not include plugins registered with .use(). Callbacks (including table renderers), binary inputs, and runtime adapters do not survive JSON stringify/parse unchanged. Store serializable schemas separately and register trusted plugins and adapters again before export.

renderDocx(schema, options?) ​

AI/LLM-friendly JSON entry point for document generation.

ts
import { renderDocx } from 'docx-kit'

const doc = await renderDocx({
  content: [
    { type: 'heading', level: 1, text: 'AI-Generated Report' },
    { type: 'paragraph', text: 'Generated from structured JSON.' },
    {
      type: 'table',
      columns: [
        { key: 'name', title: 'Name' },
        { key: 'value', title: 'Value' },
      ],
      data: [{ name: 'Foo', value: 'Bar' }],
    },
  ],
  styles: { accent: { color: '#2563eb', fontWeight: 'bold' } },
})
const blob = await doc.toBlob()

The optional second argument is RenderDocxOptions, supported by core, browser, and Node entries. pluginLoader: false rejects external npm, local, and url sources before I/O; trusted in-process inline plugins remain supported. resolveImage: false disables image-path resolution. A custom loader or image resolver replaces the platform default. Existing one-argument calls keep their behavior.

DocxSchema<TStyles> ​

ts
interface DocxSchema<TStyles extends StyleSheet = StyleSheet> {
  content: BlockNode<TStyles>[]
  page?: DocxKitConfig<TStyles>['page']
  styles?: TStyles
  plugins?: PluginSource[]
}

Released under the MIT License.