Skip to main content

KSWord Reference

KSWord is the class to extend when your LWC component needs to read or write content in Microsoft Word. All methods are async and return when the Word operation completes.

Requirements:

  • Keelstone Pro plan
  • Keelstone Word Add-in open and connected in Microsoft Word

Import

import { KSWord } from 'kstone/api';

Inserting content

ksInsertAtCursor(content, contentType?)

Inserts content at the current cursor position in the document.

async ksInsertAtCursor(content, contentType = 'text')Promise<object>
ParamTypeDefaultDescription
contentstringrequiredText or HTML to insert
contentType'text' | 'html''text'Format of the content string
// Insert plain text
await this.ksInsertAtCursor('{FirstName} {LastName}');

// Insert a formatted HTML snippet
await this.ksInsertAtCursor('<p><strong>Confidentiality.</strong> Each party agrees...</p>', 'html');

ksWrapSelection(openToken, closeToken)

Wraps the current selection with an open and close token string. Used for inserting paired template markers around highlighted text.

async ksWrapSelection(openToken, closeToken)Promise<object>
ParamTypeDescription
openTokenstringText to insert before the selection, e.g. '{#items}'
closeTokenstringText to insert after the selection, e.g. '{/items}'
// Wrap the selected paragraph in a docxtemplater loop
await this.ksWrapSelection('{#lineItems}', '{/lineItems}');

ksInsertParagraph(text, style?, insertLocation?)

Inserts a paragraph at the specified location in the document.

async ksInsertParagraph(text, style?, insertLocation = 'End')Promise<{ ok: true }>
ParamTypeDefaultDescription
textstringrequiredParagraph text
stylestring'Normal'Word paragraph style name
insertLocationstring'End''Start' | 'End' | 'Before' | 'After'

ksInsertTable(headers, rows)

Inserts a table with a header row followed by data rows.

async ksInsertTable(headers, rows)Promise<{ ok: true }>
ParamTypeDescription
headersstring[]Column header names
rowsstring[][]2D array of cell values
await this.ksInsertTable(
['Account', 'Amount', 'Stage'],
[['Acme', '$50,000', 'Closed Won'], ['Globex', '$30,000', 'Proposal']]
);

Template generation

ksGenerate(templateBase64, data, filename)

Merges a .docx template with data and inserts the result into the open Word document.

async ksGenerate(templateBase64, data, filename)Promise<string>
ParamTypeDescription
templateBase64stringBase64-encoded .docx template
dataobjectMerge context object; keys match template tokens
filenamestringFilename for the generated document

Returns: Base64 string of the merged document.

import getTemplate from '@salesforce/apex/TemplateController.getTemplate';

const templateBase64 = await getTemplate({ contentDocumentId: this.templateId });
await this.ksGenerate(templateBase64, { Name: 'Acme Corp', StartDate: '2025-01-01' }, 'Contract.docx');

ksCreateWord(sections)

Builds a .docx document from scratch (no template) and returns it as base64.

async ksCreateWord(sections)Promise<{ base64: string }>
ParamTypeDescription
sections{ children: { type: 'paragraph'|'heading'|'table', text?: string, level?: number, headers?: string[], rows?: string[][] }[] }[]Document sections

Reading the document

ksGetText()

Returns the full plain text of the document body.

async ksGetText()Promise<string>

ksGetFile()

Returns the current document as a base64-encoded .docx file. Useful for uploading the document to Salesforce Files after modifying it.

async ksGetFile()Promise<{ base64: string }>
const { base64 } = await this.ksGetFile();
await this.ksCall('/api/salesforce/files/upload', { base64, filename: 'Contract.docx', recordId: this.recordId });

ksGenerateFromData(templateKey, data, options?)

Looks up a Keelstone template by its key, merges a data object into it server-side, and inserts the result into the active document. The data object can be assembled from any combination of sources — Salesforce records, external REST API responses, computed values, or all three.

async ksGenerateFromData(templateKey, data, options = {})Promise<{ base64: string, contentDocumentId?: string }>
ParamTypeDescription
templateKeystringTemplate_Key__c on the Keelstone_Template__c record
dataobjectAny JSON-serializable object; keys become merge tokens
options.filenamestringOutput filename, e.g. 'Report.docx'
options.linkedEntityIdstringSalesforce record ID to attach the generated file to
options.outputFormatstring'pdf' to convert the output

Token mapping: data.Name{Name}, data.Owner.Name{Owner.Name}, data.Items array → {#Items}…{/Items} loop.

// Combine Salesforce data + an external REST API response
const sfRecord = await getAccountData({ recordId: this.recordId });
// e.g. { Name: 'Acme Corp', Industry: 'Tech', Owner: { Name: 'Jane Smith' } }

const pricing = await fetch('https://api.example.com/pricing/acme').then(r => r.json());
// e.g. { unitPrice: 1200, currency: 'USD', lineItems: [...] }

const result = await this.ksGenerateFromData(
'quote-template',
{ ...sfRecord, ...pricing },
{ filename: 'Acme Quote.docx', linkedEntityId: this.recordId }
);
// result.contentDocumentId — Salesforce File ID of the generated document

Content controls

Content controls are named, reusable regions in a Word document. Use them to mark sections of a document that your component can read or update by tag.

ksInsertContentControl(tag, text, title?)

Wraps the current selection in a Content Control with the specified tag.

async ksInsertContentControl(tag, text, title?)Promise<{ ok: true }>

ksGetContentControl(tag)

Reads the text of a Content Control by its tag.

async ksGetContentControl(tag)Promise<string | null>

Returns null if no Content Control with that tag exists.


ksUpdateContentControl(tag, text)

Replaces the text inside a Content Control identified by tag.

async ksUpdateContentControl(tag, text)Promise<{ ok: true }>
await this.ksUpdateContentControl('contract-status', 'Executed');

Document properties

Document properties are key/value strings stored inside the .docx file. They persist across saves and Word restarts — useful for stamping metadata (such as a Salesforce record ID or approval status) that needs to travel with the file.

ksGetDocumentProperty(key)

Reads a custom document property from the document.

async ksGetDocumentProperty(key)Promise<string | null>

Returns null if the property does not exist.

const contractId = await this.ksGetDocumentProperty('contract_record_id');

ksSetDocumentProperty(key, value)

Writes a custom document property to the document.

async ksSetDocumentProperty(key, value)Promise<object>
await this.ksSetDocumentProperty('contract_record_id', this.recordId);
await this.ksSetDocumentProperty('contract_status', 'pending_review');

ksGetAllDocumentProperties()

Reads all custom document properties from the document at once.

async ksGetAllDocumentProperties()Promise<{ [key: string]: string }>
const props = await this.ksGetAllDocumentProperties();
// { contract_record_id: '800...', contract_status: 'draft' }

Document protection

ksProtectDocument(protect)

Locks or unlocks the document to prevent direct editing. Use protect: true when submitting a document for review; use protect: false to unlock it after a decision is made.

async ksProtectDocument(protect)Promise<object>
ParamTypeDescription
protectbooleantrue to protect, false to unprotect
// Lock the document when submitting for approval
await this.ksProtectDocument(true);

// Unlock after rejection so the user can edit and resubmit
await this.ksProtectDocument(false);

Comments

ksGetComments()

Returns all document comments with their full reply thread.

async ksGetComments()Promise<Comment[]>

Returns:

[{
id: 'comment-id',
text: 'Review this clause',
authorName: 'Matthew',
resolved: false,
replies: [{ id, text, authorName }]
}]

ksGetSelectionComments()

Returns only comments anchored within the current selection. Same shape as ksGetComments().

async ksGetSelectionComments()Promise<Comment[]>

ksAddComment(text)

Inserts a comment anchored to the current selection.

async ksAddComment(text)Promise<{ id: string, ok: true }>

ksReplyToComment(commentId, text)

Adds a reply to an existing comment.

async ksReplyToComment(commentId, text)Promise<{ ok: true }>

ksResolveComment(commentId, resolved?)

Resolves or reopens a comment.

async ksResolveComment(commentId, resolved = true)Promise<{ ok: true }>

ksDeleteComment(commentId)

Deletes a comment from the document.

async ksDeleteComment(commentId)Promise<{ ok: true }>

Text analysis

ksScanForKeywords(keywords)

Searches the document for each keyword and returns match counts. Keywords with zero matches are omitted from the result.

async ksScanForKeywords(keywords)Promise<{ keyword: string, count: number }[]>
const matches = await this.ksScanForKeywords(['liability', 'indemnification', 'termination']);
// [{ keyword: 'liability', count: 3 }, { keyword: 'termination', count: 1 }]

Find, replace & formatting

ksFindReplace(find, replace, options?)

Finds all occurrences of find in the document body and replaces them with replace.

async ksFindReplace(find, replace, options = {})Promise<{ replacedCount: number }>
ParamTypeDefaultDescription
findstringrequiredText to search for
replacestringrequiredReplacement text
options.matchCasebooleanfalseCase-sensitive match
options.matchWholeWordbooleanfalseMatch whole word only

ksFormatText(format, searchText?, matchCase?)

Applies font formatting to all occurrences of searchText, or to the current selection if searchText is omitted.

async ksFormatText(format, searchText?, matchCase = false)Promise<{ ok: true }>
format fieldTypeDescription
boldbooleanBold
italicbooleanItalic
underlinebooleanSingle underline
colorstringFont colour hex
sizenumberFont size in points
highlightColorstringHighlight colour name, e.g. 'Yellow'
// Bold all occurrences of "CONFIDENTIAL"
await this.ksFormatText({ bold: true, color: '#FF0000' }, 'CONFIDENTIAL');

Images

ksInsertImage(base64, insertLocation?, options?)

Inserts an inline image into the document body.

async ksInsertImage(base64, insertLocation = 'End', options = {})Promise<{ ok: true }>
ParamTypeDescription
base64stringBase64-encoded image (PNG, JPG, etc.)
insertLocationstring'Start' | 'End' | 'Before' | 'After'
options.widthnumberWidth in points
options.heightnumberHeight in points

Headers & footers

ksGetHeaderFooter(isFooter?, type?)

Returns the text of the document header or footer.

async ksGetHeaderFooter(isFooter = false, type = 'primary')Promise<{ text: string }>

type: 'primary' | 'firstPage' | 'evenPages'


ksSetHeaderFooter(text, isFooter?, type?)

Sets the text of the document header or footer. Replaces any existing content.

async ksSetHeaderFooter(text, isFooter = false, type = 'primary')Promise<{ ok: true }>
await this.ksSetHeaderFooter('Acme Corp — Confidential', false);  // header
await this.ksSetHeaderFooter('Page', true); // footer

Breaks

ksInsertBreak(breakType?)

Inserts a break after the current selection.

async ksInsertBreak(breakType = 'page')Promise<{ ok: true }>

breakType: 'page' | 'line' | 'sectionNext' | 'sectionContinuous' | 'sectionEven' | 'sectionOdd'


Tables

ksGetTables()

Returns information about all tables in the document body.

async ksGetTables()Promise<{ tables: { index: number, rowCount: number, columnCount: number }[] }>

ksAddTableRow(tableIndex?, values?)

Adds a row to the end of a table.

async ksAddTableRow(tableIndex = 0, values?)Promise<{ ok: true }>
ParamTypeDescription
tableIndexnumberZero-based table index in the document (default 0)
valuesstring[]Cell values for the new row
await this.ksAddTableRow(0, ['Ada Lovelace', 'ada@example.com', 'Approved']);

Bookmarks

ksGetBookmarks()

Returns the names of all bookmarks in the document.

async ksGetBookmarks()Promise<{ bookmarks: string[] }>

ksInsertBookmark(name)

Inserts a bookmark at the current selection.

async ksInsertBookmark(name)Promise<{ ok: true }>

ksGoToBookmark(name)

Navigates to a bookmark and selects it.

async ksGoToBookmark(name)Promise<{ ok: true }>

ksInsertHyperlink(url, displayText?)

Inserts a hyperlink at the current selection. If displayText is provided it replaces the selection text; otherwise the selection's existing text becomes the link.

async ksInsertHyperlink(url, displayText?)Promise<{ ok: true }>
await this.ksInsertHyperlink('https://www.salesforce.com', 'View in Salesforce');

Track changes

ksTrackChanges(enabled)

Enables or disables change tracking in the document.

async ksTrackChanges(enabled)Promise<{ ok: true }>

ksAcceptAllChanges()

Accepts all tracked changes in the document.

async ksAcceptAllChanges()Promise<{ ok: true }>

ksCall(endpoint, body?)

Low-level method inherited from DocumentAPI. Call this when you need to reach a server endpoint not covered by a named method.

async ksCall(endpoint, body = {})Promise<any>

Minimal example

import { KSWord } from 'kstone/api';
import { api, track } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class ClauseInserter extends KSWord {
@api keelstoneSessionId;
@track status = '';

async handleInsert() {
try {
await this.ksInsertAtCursor(
'<p><strong>Confidentiality.</strong> Each party agrees to keep confidential all non-public information...</p>',
'html'
);
await this.ksSetDocumentProperty('last_inserted_clause', 'confidentiality');
this.status = 'Clause inserted.';
} catch (err) {
this.dispatchEvent(new ShowToastEvent({ title: 'Error', message: err.message, variant: 'error' }));
}
}
}

Flow Wiring

Wire KeelstoneSessionId from the flow to your component's keelstoneSessionId property. See Flow Wiring.