Skip to main content

KEELSTONE_INSERT

Inserts a complete Excel workbook into the active Excel file. All worksheets from the provided .xlsx are appended at the end of the current workbook.

Payload

{
type: 'KEELSTONE_INSERT';
base64: string; // Base64-encoded .xlsx file
filename: string; // Display name (not used for insertion, but saved to SF Files)
}
FieldTypeDescription
type'KEELSTONE_INSERT'Discriminator — must be exactly this string
base64stringThe merged .xlsx encoded as base64
filenamestringFilename used when saving back to Salesforce Files

What Excel does

Excel.run((context) => {
context.workbook.insertWorksheetsFromBase64(base64, {
positionType: Excel.WorksheetPositionType.end
});
return context.sync();
});

All sheets in the provided workbook are inserted after the last existing sheet. The active sheet does not change.

Firing the event from your LWC

// myComponent.js
import { LightningElement } from 'lwc';

export default class MyComponent extends LightningElement {
handleGenerateClick() {
// ... build your base64 workbook ...
const payload = {
type: 'KEELSTONE_INSERT',
base64: myBase64String,
filename: 'My Report.xlsx'
};

// Fire both channels
try { window.parent.postMessage(payload, '*'); } catch (e) {}
document.dispatchEvent(new CustomEvent('keelstoneinsert', {
detail: payload,
bubbles: true
}));
}
}

Generating the base64 workbook

The recommended approach is to send your template and data to the Keelstone document generation endpoint and use the base64 from the response:

const response = await fetch('https://app.keelstone.dev/api/docs/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
templateBase64: myTemplateBase64,
data: { account: accountRecord, contacts: contactList }
})
});
const { base64 } = await response.json();

See POST /api/docs/generate for full request/response details.

Example: complete LWC that generates and inserts

// reportGenerator.js
import { LightningElement, api, wire } from 'lwc';
import getTemplate from '@salesforce/apex/ExcelTemplateController.getTemplate';

export default class ReportGenerator extends LightningElement {
@api templateId;
@api mergeData;
@api filename = 'Report.xlsx';

isProcessing = false;
error = null;

connectedCallback() {
this.generate();
}

async generate() {
this.isProcessing = true;
try {
// 1. Fetch template from SF Files
const templateBase64 = await getTemplate({ contentDocumentId: this.templateId });

// 2. Merge via server
const resp = await fetch('https://app.keelstone.dev/api/docs/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
templateBase64,
data: JSON.parse(this.mergeData)
})
});
if (!resp.ok) throw new Error(`Server error ${resp.status}`);
const { base64 } = await resp.json();

// 3. Send to Excel
const payload = { type: 'KEELSTONE_INSERT', base64, filename: this.filename };
try { window.parent.postMessage(payload, '*'); } catch (e) {}
document.dispatchEvent(new CustomEvent('keelstoneinsert', { detail: payload, bubbles: true }));

} catch (err) {
this.error = err.message || 'An error occurred';
} finally {
this.isProcessing = false;
}
}
}