Besides holding cell data, an Excel workbook is often used as a container for files: a quotation carries a Word version of the contract terms, a product sheet carries a PDF datasheet, and double-clicking the object opens the source file directly. Files embedded into a worksheet like this are OLE objects (Object Linking and Embedding). Inserting one by hand takes two steps in the Excel UI—Insert → Object—but doing it from code in the browser needs a dedicated API.Spire.XLS for JavaScript performs this work directly in the browser through WebAssembly, managing input and output files with a virtual file system (VFS) and requiring no backend service.
This article covers two key features:
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is already installed and the WebAssembly module has been initialized.
Insert an OLE Object in Excel
OleObjects.Add inserts an external file into a worksheet. It takes three arguments: the file to embed, the icon the object shows on the sheet, and the link type—OleLinkType.Embed embeds the file into the workbook, OleLinkType.Link inserts it as a link. After the object is in place, Location decides which cell it is anchored to and ObjectType declares what was embedded, which is how Excel knows which program to use when the object is double-clicked. The steps are:
- Create a new workbook and write a caption into a cell.
- Open the workbook to be embedded and render its worksheet to an image, to use as the display icon.
- Embed that Excel file into the worksheet with
OleObjects.Add. - Set
LocationandObjectType. - Save the workbook.
Here is a complete code example that inserts an Excel file into a worksheet as an OLE object in React:
function App() {
const insertOleObject = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font into VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file to be embedded into VFS
const embeddedFileName = 'OLEObjects.xlsx';
await window.spire.FetchFileToVFS(embeddedFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Create a new workbook and write the caption
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
sheet.Range.get("A1").Text = "Here is an OLE object.";
// Open the embedded workbook and render its worksheet to an image as the display icon
const embeddedBook = new xlsModule.Workbook();
embeddedBook.LoadFromFile(embeddedFileName);
const embeddedSheet = embeddedBook.Worksheets.get(0);
embeddedSheet.PageSetup.LeftMargin = 0;
embeddedSheet.PageSetup.RightMargin = 0;
embeddedSheet.PageSetup.TopMargin = 0;
embeddedSheet.PageSetup.BottomMargin = 0;
const image = embeddedSheet.ToImage(1, 1, 19, 5);
embeddedBook.Dispose();
// Embed the Excel file into the worksheet; the file data is stored with the workbook
const oleObject = sheet.OleObjects.Add(
embeddedFileName,
image,
xlsModule.OleLinkType.Embed
);
// Anchor the object at cell B4 and declare it as an Excel worksheet
oleObject.Location = sheet.Range.get("B4");
oleObject.ObjectType = xlsModule.OleObjectType.ExcelWorksheet;
// Save the workbook
const outputFileName = "InsertOLEObject.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the result file from VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Insert an OLE Object</h1>
<button onClick={insertOleObject}>Start</button>
</div>
);
}
export default App;
The icon here is taken directly from the rendered embedded worksheet, so the OLE object shows its own content on the sheet. Switching ObjectType to values such as OleObjectType.WordDocument or OleObjectType.AdobeAcrobatDocument declares other kinds of embedded files.
Running it, the effect of inserting a workbook as an OLE object:

Insert an OLE Object with a Custom Icon
ToImage has to open a workbook and render a row/column range every time, which suits cases where the object should present its own content; when a single icon should be applied to every attachment, reading a ready-made picture is simpler, and the same picture can be reused across attachments. The second argument of OleObjects.Add accepts both kinds of input. The steps are:
- Load the icon image and the attachment file into VFS.
- Create a new workbook and read the icon image into a stream with
new xlsModule.Stream. - Insert the attachment as an embedded object with
OleObjects.Add, passing the icon stream. - Set
LocationandObjectType. - Save the workbook.
Here is a complete code example that inserts a PDF attachment with a custom icon in React:
function App() {
const insertOleObjectWithIcon = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font into VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the icon image and the attachment into VFS
const iconFileName = 'OLEIcon.png';
const attachmentFileName = 'Attachment.pdf';
await window.spire.FetchFileToVFS(iconFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
await window.spire.FetchFileToVFS(attachmentFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Create a new workbook
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
// Read the icon image as a stream to use as the display icon of the OLE object
const iconStream = new xlsModule.Stream(iconFileName);
// Embed the PDF attachment into the worksheet
const oleObject = sheet.OleObjects.Add(
attachmentFileName,
iconStream,
xlsModule.OleLinkType.Embed
);
// Anchor the object at cell B4 and declare it as a PDF document
oleObject.Location = sheet.Range.get("B4");
oleObject.ObjectType = xlsModule.OleObjectType.AdobeAcrobatDocument;
// Save the workbook
const outputFileName = "InsertOLEObjectWithIcon.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the result file from VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Insert an OLE Object with a Custom Icon</h1>
<button onClick={insertOleObjectWithIcon}>Start</button>
</div>
);
}
export default App;
Running it, the effect of inserting a PDF attachment with a custom icon as an OLE object:

FAQ
Only a blank icon shows up on the sheet after inserting?
Cause: The second argument of OleObjects.Add decides the icon an OLE object shows on the sheet. When the image comes from ToImage, a region that falls outside the used range of the worksheet yields a blank picture, so the inserted object also shows only blank space.
Solution: Keep the region inside the part of the sheet that actually has content, or use a ready-made image file instead:
// Use a fixed picture as the icon, independent of the worksheet content
const iconStream = new xlsModule.Stream('OLEIcon.png');
const oleObject = sheet.OleObjects.Add('Attachment.pdf', iconStream, xlsModule.OleLinkType.Embed);
oleObject.Location = sheet.Range.get("B4");
oleObject.ObjectType = xlsModule.OleObjectType.AdobeAcrobatDocument;
What happens if ObjectType is set to something else?
Cause: ObjectType is not merely a comment—its value is written into the progId field of the workbook, and Excel uses that identifier to find the right program when the object is double-clicked. The same PDF attachment declares a progId of Acrobat Document under OleObjectType.AdobeAcrobatDocument; declare it as OleObjectType.ExcelWorksheet and the progId becomes Worksheet, so Excel attempts to open the PDF with Excel itself, and the object will not open.
Solution: Set ObjectType to the real type of the embedded file. The common values are:
| Embedded file | ObjectType |
|---|---|
| Excel workbook | OleObjectType.ExcelWorksheet |
| Word document | OleObjectType.WordDocument |
| PowerPoint presentation | OleObjectType.PowerPointSlide |
| PDF document | OleObjectType.AdobeAcrobatDocument |
// Declare the real file type so Excel opens it with the right program
oleObject.ObjectType = xlsModule.OleObjectType.AdobeAcrobatDocument;
Get a Free License
Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.
