office-engine

API

React

import { DocViewer } from '@p10node/office-engine'

<DocViewer src={file} style={{ height: 600 }} />                 // File | Blob | ArrayBuffer | Uint8Array
<DocViewer src="https://cdn.example.com/report.xlsx" />          // URL → Range requests
<DocViewer src={url} headers={{ Authorization: `Bearer ${t}` }} credentials="include" />
<DocViewer src={file} editable onSave={(blob, name) => upload(blob, name)} />  // editing
<DocViewer src={file} allowSave={false} allowDownload={false} />  // no Save/Download, no image download
<DocViewer src={file} fileMenu={false} />                         // no File menu

File menu

ItemDOCXXLSXPPTX
Newblank documentblank spreadsheetblank presentation
Open… (Ctrl+O)any supported fileany supported fileany supported file
Import CSV into new sheet–.csv / .tsv–
Save (Ctrl+S)✓✓✓
Rename…✓✓✓
Download as (native).docx.xlsx.pptx
PDFpages as showncurrent sheet, fit to widthone slide per page
Web page.html, images inlined.html.html, images inlined
Text.txt, .md.csv, .tsv (current sheet).txt (incl. notes)
Document detailspages, words, characterssheets, used rangeslides, slide size
Print (Ctrl+P)✓✓✓
Host items, ClosefileMenuItems, onClosefileMenuItems, onClosefileMenuItems, onClose

Open converts other formats: .csv / .tsv → workbook, .txt / .md / .html → document (headings, lists, bold / italic, links). Converted files start unsaved; Save writes the Office file. New / Open replace the shown document until the host passes another src (unsaved changes are confirmed first; both are hidden during collaboration). Rename changes the shown name and the name used by Save / Download (onRename receives it); it does not reload the document. Document details also lists the file's core properties (title, author, created, modified…). PDF goes through the browser print dialog ("Save as PDF"), so text stays selectable. allowDownload={false} also hides Download as / Print and blocks Ctrl+P.

<DocViewer
  src={file}
  fileMenuItems={[{ label: 'Share…', icon: 'open', onClick: share }, { label: 'Version history', onClick: history }]}
  onRename={(name) => api.rename(id, name)}
  onClose={() => router.back()}
/>

CSS is auto-injected, no import needed. Container must have a height.

PropTypeDefaultNotes
srcFile | Blob | ArrayBuffer | string | URL–Document source
namestringautoDisplay name
toolbarbooleantrueTop bar (name, status, progress)
toolbarExtraReactNode–Extra buttons on the right of the toolbar
zoomnumber | 'fit''fit'Initial zoom (docx/pptx)
thumbnailsbooleantrueThumbnail column for pptx
headersRecord<string,string>–Headers for URL requests
credentialsRequestCredentials–Cross-origin cookies
worker() => Worker | falseinlineCustom worker (CSP), false = main thread
styleTargetDocument | ShadowRootdocumentWhere CSS is injected
editablebooleanfalseOpen in edit mode
allowEditbooleantrueShow Edit/View button
allowSavebooleantrueShow Save/Download button, enable Ctrl+S
allowDownloadbooleantrueAllow downloads to device (save without onSave, images)
fileMenubooleantrueFile menu: open, download as PDF / HTML / text, print
allowOpenbooleantrueFile → New / Open (off during collaboration)
fileMenuItemsFileMenuItem[]–Extra File menu entries (label, onClick, icon, hint)
onRename(name) => void–File → Rename result (extension included)
onClose() => void–Adds File → Close
onSave(blob, name) => voiddownloadReceives saved file (downloads by default)
onDirtyChange(dirty) => void–Whether there are unsaved changes
collabCollabOptions–Real-time collaboration, see collaboration
onLoad(client) => void–
onError(error) => void–

Use individual views / build your own UI:

import { useDocument, DocxView, XlsxView, PptxView } from '@p10node/office-engine'

const { client, error, progress } = useDocument(src)
if (client?.kind === 'xlsx') return <div className="de-root"><XlsxView client={client} /></div>

Without a React build

<script src="office-engine.embed.js"></script>   <!-- dist/, bundles React + worker -->

<office-viewer src="/files/report.docx" style="height:600px"></office-viewer>

<div id="v" style="height:600px"></div>
<script>
  const viewer = OfficeEngine.mount(document.getElementById('v'), { src: '/files/deck.pptx' })
  input.onchange = (e) => viewer.update({ src: e.target.files[0] })
  // viewer.destroy()
</script>

<office-viewer>: attributes src, name, editable, toolbar="false", thumbnails="false", save="false", download="false", file-menu="false", open="false", collab / room / user / base (real-time collaboration); property .file = File; events load, error.

Core API (no React)

import { DocumentClient } from '@p10node/office-engine/core'

const doc = await DocumentClient.open(fileOrUrl, { onProgress: console.log })
doc.kind                                   // 'docx' | 'xlsx' | 'pptx'
doc.on('docx:blocks', (blocks) => {})      // docx: streamed blocks
await doc.call('docx.start')
doc.call('xlsx.load', 0)                   // xlsx: stream sheet
doc.on('xlsx:progress', (p) => {})
await doc.call('xlsx.block', 0, 1000, 1100) // formatted cells, rows [1000, 1100)
await doc.call('pptx.slide', 12)           // slide model with layout/master/theme resolved
await doc.call('xlsx.set', 0, [{ r: 4, c: 1, input: '=SUM(A1:A4)' }])
const blob = await doc.call('save')        // edited file
doc.destroy()

CSP

The default worker is an inline blob → requires worker-src blob:. If that's not allowed, host dist/office-engine.worker.js (exported as @p10node/office-engine/worker) on the same origin:

<DocViewer src={src} worker={() => new Worker('/static/office-engine.worker.js', { type: 'module' })} />