Skip to main content

KEELSTONE_WRITE

Writes a 2D array of values to a specific location in the active workbook. By default, the written range is also converted to an Excel Table and registered as a named range — enabling the KEELSTONE_SAVE_TABLES round-trip. Pass namedRange: false to write data only, with no table or named range created.

The taskpane responds with KEELSTONE_WRITE_RESULT after the write completes.

Payload

{
type: 'KEELSTONE_WRITE';
data: (string | number | boolean | null)[][];
target?: string;
namedRange?: boolean; // default true
}
FieldTypeRequiredDescription
type'KEELSTONE_WRITE'YesDiscriminator
data2D arrayYesRows and columns to write. First row is treated as headers when namedRange is true
targetstringNoWhere to write. See Target resolution
namedRangebooleanNoDefault true. When true, wraps the written range in an Excel Table and creates a named range with an auto-generated KS_ name

Target resolution

target valueResolves to
undefined or ""Cell A1 of the active worksheet
"B3"Cell B3 on the active worksheet
"Sheet1!B3"Cell B3 on sheet Sheet1
"'My Sheet'!C5"Cell C5 on a sheet named My Sheet
"MyNamedRange"The existing named range MyNamedRange

The write range is sized to fit data automatically.

Response: KEELSTONE_WRITE_RESULT

The taskpane posts this back to the LWC after the write completes.

{
type: 'KEELSTONE_WRITE_RESULT';
tableName: string | null; // null when namedRange is false
address: string; // e.g. "Sheet1!A1:D11"
rowCount: number; // data rows written, excluding the header row
}

Listen for it in your LWC:

window.addEventListener('message', (event) => {
if (event.data?.type === 'KEELSTONE_WRITE_RESULT') {
const { tableName, address, rowCount } = event.data;
console.log(`Wrote ${rowCount} rows to ${address} as table "${tableName}"`);
}
});

Examples

Write query results to the active sheet with a table and named range (default):

window.parent.postMessage({
type: 'KEELSTONE_WRITE',
data: [
['Id', 'Name', 'Phone'],
['001...', 'Acme Corp', '555-0101'],
['001...', 'Globex', '555-0102'],
],
target: 'A1',
}, '*');
// namedRange defaults to true → Excel Table + named range created
// Response: KEELSTONE_WRITE_RESULT { tableName: 'KS_1714000000', address: 'Sheet1!A1:C3', rowCount: 2 }

Write data only — no table, no named range:

window.parent.postMessage({
type: 'KEELSTONE_WRITE',
data: [
['Acme Corp', 1250000, '2024-Q4'],
['Globex', 875000, '2024-Q4'],
],
target: 'Summary!B5',
namedRange: false,
}, '*');
// Response: KEELSTONE_WRITE_RESULT { tableName: null, address: 'Summary!B5:D6', rowCount: 2 }

Write to a named range in the workbook:

window.parent.postMessage({
type: 'KEELSTONE_WRITE',
data: [
['Metric', 'Value'],
['Total Revenue', 4500000],
['Open Opportunities', 23],
],
target: 'DashboardRange',
namedRange: false,
}, '*');

Data types

Excel accepts strings, numbers, booleans, and null. Dates should be passed as ISO strings ("2024-01-15") — Excel displays them as text unless the cell is formatted as a date.

// Good
['2024-01-15', 42500.00, true, null]

// Avoid — Date objects are not serializable over postMessage
[new Date(), ...]

Named ranges and save round-trip

When namedRange: true, the taskpane:

  1. Calls context.workbook.tables.add(range, true) — first row becomes column headers
  2. Assigns a unique name: KS_ + timestamp
  3. Calls context.workbook.names.add(tableName, range)

This makes the table discoverable by KEELSTONE_SAVE_TABLES, which reads all KS_ tables on the active sheet and sends their data to /api/data/save. See KEELSTONE_SAVE_TABLES for the full round-trip.