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>
| Param | Type | Default | Description |
|---|---|---|---|
content | string | required | Text 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>
| Param | Type | Description |
|---|---|---|
openToken | string | Text to insert before the selection, e.g. '{#items}' |
closeToken | string | Text 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 }>
| Param | Type | Default | Description |
|---|---|---|---|
text | string | required | Paragraph text |
style | string | 'Normal' | Word paragraph style name |
insertLocation | string | '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 }>
| Param | Type | Description |
|---|---|---|
headers | string[] | Column header names |
rows | string[][] | 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>
| Param | Type | Description |
|---|---|---|
templateBase64 | string | Base64-encoded .docx template |
data | object | Merge context object; keys match template tokens |
filename | string | Filename 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 }>
| Param | Type | Description |
|---|---|---|
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 }>
| Param | Type | Description |
|---|---|---|
templateKey | string | Template_Key__c on the Keelstone_Template__c record |
data | object | Any JSON-serializable object; keys become merge tokens |
options.filename | string | Output filename, e.g. 'Report.docx' |
options.linkedEntityId | string | Salesforce record ID to attach the generated file to |
options.outputFormat | string | '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>
| Param | Type | Description |
|---|---|---|
protect | boolean | true 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 }>
| Param | Type | Default | Description |
|---|---|---|---|
find | string | required | Text to search for |
replace | string | required | Replacement text |
options.matchCase | boolean | false | Case-sensitive match |
options.matchWholeWord | boolean | false | Match 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 field | Type | Description |
|---|---|---|
bold | boolean | Bold |
italic | boolean | Italic |
underline | boolean | Single underline |
color | string | Font colour hex |
size | number | Font size in points |
highlightColor | string | Highlight 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 }>
| Param | Type | Description |
|---|---|---|
base64 | string | Base64-encoded image (PNG, JPG, etc.) |
insertLocation | string | 'Start' | 'End' | 'Before' | 'After' |
options.width | number | Width in points |
options.height | number | Height 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 }>
| Param | Type | Description |
|---|---|---|
tableIndex | number | Zero-based table index in the document (default 0) |
values | string[] | 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 }>
Hyperlinks
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.