Story · Demo
The full workbook viewer
Unlike slides and pages, a spreadsheet is one continuous grid — so XlsxViewer owns its own canvas, sheet-tab bar and zoom slider. Switch sheets along the bottom, click-drag to select a range, press Ctrl/Cmd+C to copy it as TSV, and drag the zoom slider (10–400%).
import { XlsxViewer } from '@silurus/ooxml/xlsx';
// XlsxViewer owns its canvas, sheet-tab bar and zoom slider — hand it a
// container element (not a canvas). Click-drag selects a range; Ctrl/Cmd+C
// copies it as TSV.
const container = document.getElementById('sheet') as HTMLElement;
const viewer = new XlsxViewer(container, { showZoomSlider: true });
await viewer.load('/sample.xlsx'); In your framework
Mount it in a container
The viewer is a plain TypeScript class — no framework runtime, no peer deps. Create it on mount,
call load(), and let it go on unmount.
import { useEffect, useRef } from 'react';
import { XlsxViewer } from '@silurus/ooxml/xlsx';
export function Viewer({ src }: { src: string }) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const container = ref.current;
if (!container) return;
const viewer = new XlsxViewer(container, { showZoomSlider: true });
void viewer.load(src);
return () => viewer.destroy();
}, [src]);
return <div ref={ref} />;
} <script setup lang="ts">
import { onMounted, onBeforeUnmount, ref } from 'vue';
import { XlsxViewer } from '@silurus/ooxml/xlsx';
const props = defineProps<{ src: string }>();
const container = ref<HTMLDivElement>();
let viewer: XlsxViewer | undefined;
onMounted(() => {
viewer = new XlsxViewer(container.value as HTMLDivElement, { showZoomSlider: true });
void viewer.load(props.src);
});
onBeforeUnmount(() => viewer?.destroy());
</script>
<template>
<div ref="container" />
</template> <script lang="ts">
import { onMount } from 'svelte';
import { XlsxViewer } from '@silurus/ooxml/xlsx';
export let src: string;
let container: HTMLDivElement;
onMount(() => {
const viewer = new XlsxViewer(container, { showZoomSlider: true });
void viewer.load(src);
return () => viewer.destroy();
});
</script>
<div bind:this={container}></div> import { XlsxViewer } from '@silurus/ooxml/xlsx';
const container = document.getElementById('viewer') as HTMLDivElement;
const viewer = new XlsxViewer(container, { showZoomSlider: true });
await viewer.load('/sample.xlsx'); API reference
Options & methods
Every public option and method, straight from the source. Types omitted for brevity are exported from the package — your editor will autocomplete the rest.
XlsxViewer
Full workbook viewer. Takes a container <div> (not a canvas) — it manages its own canvas, sheet-tab bar and zoom slider.
new XlsxViewer(container: HTMLElement, options?: XlsxViewerOptions) Options
| Option | Type | Default | Description |
|---|---|---|---|
cellScale | number | 1 | Scale factor for cell/header dimensions (0.5 = half size). |
showZoomSlider | boolean | true | Show the Excel-style zoom slider at the end of the tab bar. |
zoomMin / zoomMax | number | 0.1 / 4 | Zoom slider bounds as scale factors (10%–400%). |
useGoogleFonts | boolean | false | Load metric-compatible webfonts from Google Fonts so layout matches Office without the fonts installed. Off by default for privacy. |
maxZipEntryBytes | number | 512 MiB | Per-entry ZIP decompression cap (zip-bomb guard). Lower it for untrusted input. |
onReady | (sheetNames: string[]) => void | — | Called once the workbook is parsed. |
onSheetChange | (index: number, name: string) => void | — | Called when the active sheet changes. |
onSelectionChange | (sel: CellRange | null) => void | — | Called when the selected range changes; null clears it. |
onError | (err: Error) => void | — | Called on parse or render errors. |
Methods
load(source: string | ArrayBuffer): Promise<void> | Load a workbook from a URL or ArrayBuffer and render the first sheet. |
goToSheet(index: number): Promise<void> | Show a specific sheet (0-indexed, clamped). |
nextSheet(): Promise<void> | Advance one sheet. |
prevSheet(): Promise<void> | Go back one sheet. |
get sheetIndex(): number | Current sheet index. |
get sheetCount(): number | Total sheets (0 until loaded). |
get sheetNames(): string[] | Names of all sheets. |
get selection(): CellRange | null | The current selected range. |
getCellAt(clientX: number, clientY: number): CellAddress | null | Hit-test a viewport coordinate to a cell address. |
get canvasElement(): HTMLCanvasElement | The underlying canvas the grid is drawn on. |
destroy(): void | Tear down the worker and release resources. |
XlsxWorkbook
Headless engine — parse once, render any sheet viewport into any canvas you supply.
await XlsxWorkbook.load(source, options?) Options
| Option | Type | Default | Description |
|---|---|---|---|
useGoogleFonts | boolean | false | Load metric-compatible webfonts from Google Fonts so layout matches Office without the fonts installed. Off by default for privacy. |
maxZipEntryBytes | number | 512 MiB | Per-entry ZIP decompression cap (zip-bomb guard). Lower it for untrusted input. |
Methods
static load(source, options?): Promise<XlsxWorkbook> | Parse a workbook from a URL or ArrayBuffer. |
get sheetNames(): string[] | Names of all sheets. |
get sheetCount(): number | Total sheets. |
renderViewport(canvas, sheetIndex, viewport, opts?): Promise<void> | Render a row/col window of a sheet into the given canvas. |
destroy(): void | Release the worker. |