npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@worksheet-js/core

v1.4.0

Published

The high-performance, virtualized spreadsheet UI engine for modern web applications.

Readme

@worksheet-js/core

Industrial-grade, high-performance spreadsheet engine for the modern web.

npm version npm downloads TypeScript License

@worksheet-js/core is the foundational engine behind the Worksheet.js ecosystem. It delivers a virtualized canvas renderer, a robust sheet state model, background formula recalculation via Web Workers, and a comprehensive public API for building professional-grade spreadsheet applications.


Table of Contents


Key Features

  • Canvas Tile Renderer — Virtualized dirty-tile rendering; only changed tiles repaint on scroll.
  • 1M+ Cells at 60 FPS — No DOM cell pool; pure canvas operations with hardware acceleration.
  • Progressive Loading — First ~300 rows rendered immediately; remaining rows hydrate in the background.
  • Background Formula Engine — Calculations run in a dedicated Web Worker via CalcWorkerHost.
  • 300+ Excel Functions — Powered by @worksheet-js/formula with full cross-sheet dependency tracking.
  • High-Fidelity XLSX I/O — Round-trip import/export preserving styles, merges, conditional formatting, and hyperlinks.
  • Plugin System — Charts (Chart.js 4.x), Pivot Tables, Data Validation, Conditional Formatting, Comments, Images.
  • Freeze Panes — Per-axis frozen row/column rendering with correct hit-test support.
  • Find & Replace — Full-sheet search with match highlighting.
  • Performance Monitoring — Built-in rolling-window P95/mean/max telemetry across 6 metrics.
  • LRU Display Cache — Bounded at 100K entries with proactive eviction on scroll.
  • Fully Type-Safe — Strict TypeScript with exhaustive type definitions for all public surfaces.

Installation

npm install @worksheet-js/core chart.js
# or
pnpm add @worksheet-js/core chart.js
# or
yarn add @worksheet-js/core chart.js

Required peer dependency: chart.js >= 4.0.0 must be installed for the integrated charting plugin. Install it even if you are not using charts.

Framework wrappers (recommended for React/Vue projects):

# React
npm install @worksheet-js/core @worksheet-js/react chart.js

# Vue 3
npm install @worksheet-js/core @worksheet-js/vue chart.js

License Initialization

@worksheet-js/core is proprietary software. A license key must be initialized once at application startup, before calling Worksheet.create() or any other API.

import { initializeLicense } from '@worksheet-js/core';

// Call this once at your application's entry point
initializeLicense('YOUR-LICENSE-KEY');

Alternatively, pass the key inline via WorksheetOptions:

const sheet = await Worksheet.create({
  container: document.getElementById('app')!,
  licenseKey: 'YOUR-LICENSE-KEY',
  worksheets: [{ worksheetName: 'Sheet1' }],
});

To obtain a license key, contact [email protected].


Quick Start

import { Worksheet, initializeLicense } from '@worksheet-js/core';

// 1. Initialize your license
initializeLicense('YOUR-LICENSE-KEY');

// 2. Create the spreadsheet instance
const sheet = await Worksheet.create({
  container: document.getElementById('app')!,
  worksheets: [
    {
      worksheetName: 'Annual Report',
      minDimensions: [26, 1000], // 26 columns (A–Z), 1000 rows
    },
  ],
  toolbar: true,
  formulaBar: true,
  theme: 'light',
});

// 3. Write values and formulas
sheet.setValue('A1', 'Product');
sheet.setValue('B1', 'Revenue');
sheet.setValue('B2', '15000');
sheet.setValue('B3', '=SUM(B2:B100)');

// 4. Apply styles
sheet.setStyle('A1', { bold: true, color: '#1a1a2e', backgroundColor: '#e8f4f8' });

// 5. Listen for changes
sheet.on('onchange', (ws, cell, x, y, value) => {
  console.log(`Cell [${x},${y}] changed to: ${value}`);
});

Configuration Options

All options are passed as WorksheetOptions to Worksheet.create().

| Option | Type | Default | Description | | :----------------- | :----------------------------- | :-------: | :--------------------------------------------------------------------- | | container | HTMLElement | — | Required. DOM element to mount the spreadsheet into. | | worksheets | Partial<SheetMeta>[] | [{}] | Initial sheet tab configuration (name, dimensions, frozen panes). | | toolbar | boolean | true | Show the ribbon toolbar. | | formulaBar | boolean | true | Show the formula input bar above the grid. | | theme | 'light' \| 'dark' | 'light' | Color theme. | | defaultColWidth | number | 100 | Default column width in pixels. | | defaultRowHeight | number | 24 | Default row height in pixels. | | frozenRows | number | 0 | Rows to freeze at the top (applies globally across all sheets). | | frozenCols | number | 0 | Columns to freeze at the left (applies globally across all sheets). | | licenseKey | string | — | License key (alternative to calling initializeLicense() separately). | | onSave | (data: any) => Promise<void> | — | Callback when the user triggers Save (Ctrl+S or toolbar save button). |

SheetMeta — per-sheet configuration

| Property | Type | Description | | :-------------- | :----------------------------- | :-------------------------------------- | | worksheetName | string | Tab display name. | | minDimensions | [cols: number, rows: number] | Minimum grid size to render. | | frozenRows | number | Rows frozen for this specific sheet. | | frozenCols | number | Columns frozen for this specific sheet. | | hidden | boolean | Hide the sheet tab from the tab bar. |


Public API

Static Methods

// Create a new spreadsheet instance and mount it into the DOM
Worksheet.create(options: WorksheetOptions): Promise<Worksheet>

// Load an XLSX file from a binary buffer
Worksheet.loadXlsx(buffer: Uint8Array, options: WorksheetOptions): Promise<Worksheet>

// Load from CSV text or binary
Worksheet.loadCsv(data: string | Uint8Array, options: WorksheetOptions): Promise<Worksheet>

// Load from JSON data
Worksheet.loadJson(data: any, options: WorksheetOptions): Promise<Worksheet>

Data Methods

// Read a cell value by address (e.g. 'A1') or by zero-based coordinates
getValue(address: string): string
getValue(x: number, y: number): string

// Write a value or formula to a cell
setValue(address: string, value: string): void
setValue(x: number, y: number, value: string): void

// Read the computed style of a cell
getStyle(address: string): Partial<CellStyle>

// Apply style properties to a cell (partial — only specified keys are changed)
setStyle(address: string, style: Partial<CellStyle>): void
setStyle(x: number, y: number, style: Partial<CellStyle>): void

Worksheet Management

// The currently active sheet model (read-only)
get activeWorksheet(): WorksheetModel | null

// Switch the active tab by zero-based index
setActiveWorksheet(index: number): void

// Add a new sheet tab
addWorksheet(options?: Partial<SheetMeta>): Promise<WorksheetModel | null>

// Permanently remove a sheet tab
deleteWorksheet(index: number): void

// Duplicate an existing sheet
duplicateWorksheet(index: number): Promise<void>

// Move a sheet tab from one position to another
moveWorksheet(fromIdx: number, toIdx: number): void

// Rename a sheet tab
renameWorksheet(index: number, name: string): void

// Hide / unhide a sheet tab
hideWorksheet(index: number): void
unhideWorksheet(index: number): void

Navigation & View

// Scroll to a specific row (y) and optionally column (x) — zero-based
goto(y: number, x?: number): void

// Directional navigation (moves selection cursor)
left(): void
right(): void
top(): void
down(): void
first(): void   // Jump to A1
last(): void    // Jump to the last non-empty cell

// Resize the viewport container
setViewport(width: number | string, height: number | string): void

// Enter or exit fullscreen mode
fullscreen(state: boolean): void

// Read the current zoom level (percentage, e.g. 100)
getZoom(): number

// Set the zoom level (e.g. 75, 100, 125, 150)
setZoom(value: number): void

// Switch color theme
setTheme(theme: 'light' | 'dark'): void

// Override theme color tokens
setColors(colors: Partial<ThemeColors>): void

// Override theme font stack
setFonts(fonts: ThemeFonts): void

// Change the default font family
setDefaultFont(displayName: string, cssFamily?: string): void

Formulas & Computation

// Enable or disable background formula recalculation
calculations(state: boolean): void

// Evaluate a formula expression ad-hoc (not stored in any cell)
executeFormula(expression: string, x?: number, y?: number, caching?: boolean): unknown

// Read from the volatile per-cell cache
getCache(cellName: string): unknown

// Write to the volatile per-cell cache (single entry or batch)
setCache(cellName: string, value: unknown): void
setCache(entries: Record<string, unknown>): void

Import & Export

// Import an XLSX or CSV file from a browser File object (format auto-detected)
importFromFile(file: File): Promise<void>

// Export the workbook as a downloadable XLSX file
exportXlsx(filename?: string): Promise<void>

// Export the active sheet as a downloadable CSV file
exportCsv(filename?: string): Promise<void>

// Trigger the configured onSave callback (or fall back to a download)
save(): Promise<void>

// Mark the workbook as having unsaved changes
markDirty(): void

// Check whether the workbook has unsaved changes
isDirty(): boolean

Performance

Built-in rolling-window telemetry tracks 6 metrics with P95, mean, and max statistics.

// Snapshot all current performance metrics
getPerfSnapshot(): PerfSnapshot

// Reset all rolling windows before starting a benchmark
resetPerfCounters(): void

PerfSnapshot shape:

interface PerfSnapshot {
  renderMs: { p95: number; mean: number; max: number };
  paintMs: { p95: number; mean: number; max: number };
  scrollFps: { p95: number; mean: number; max: number };
  inputLatencyMs: { p95: number; mean: number; max: number };
  formulaMs: { p95: number; mean: number; max: number };
  estimatedCellMemoryKB: { p95: number; mean: number; max: number };
}

Example:

sheet.resetPerfCounters();
// ... run your workload ...
const snap = sheet.getPerfSnapshot();
console.log('P95 render time:', snap.renderMs.p95, 'ms');
console.log('Mean scroll FPS:', snap.scrollFps.mean);
console.log('Formula P95:', snap.formulaMs.p95, 'ms');

Lifecycle

// Attach an event listener
on(event: string, callback: (...args: any[]) => void): void

// Remove an event listener
off(event: string, callback: (...args: any[]) => void): void

// Emit an event manually
emit(event: string, ...args: any[]): boolean

// Destroy the instance — unmounts from DOM and releases the Web Worker
destroy(): void

Event System

Register listeners with sheet.on(eventName, handler). All events pass the active WorksheetModel as the first argument.

Core Events

| Event | Callback Signature | Description | | :--------------- | :-------------------------------------------------------------------------- | :-------------------------------------------- | | onload | (ws: WorksheetModel) => void | Fired after the spreadsheet is fully mounted. | | onchange | (ws, cell, x: number, y: number, value: string, oldValue: string) => void | Cell value changed. | | onselection | (ws, x1: number, y1: number, x2: number, y2: number) => void | Selection range changed. | | oncreate | (ws: WorksheetModel) => void | A new sheet was created. | | oneditionstart | (ws, x: number, y: number) => void | Cell edit mode started. | | oneditionend | (ws, x: number, y: number, value: string) => void | Cell edit mode committed. | | oneditioninput | (ws, x: number, y: number, value: string) => void | Keystroke inside the cell editor. | | onfocus | (ws: WorksheetModel) => void | Spreadsheet received focus. | | onblur | (ws: WorksheetModel) => void | Spreadsheet lost focus. | | onundo | (ws: WorksheetModel) => void | Undo was performed. | | onredo | (ws: WorksheetModel) => void | Redo was performed. |

Structural Events

| Event | Callback Signature | Description | | :--------------- | :----------------------------------------------- | :---------------- | | oninsertrow | (ws, rowIndex: number, count: number) => void | Rows inserted. | | ondeleterow | (ws, rowIndex: number, count: number) => void | Rows deleted. | | oninsertcolumn | (ws, colIndex: number, count: number) => void | Columns inserted. | | ondeletecolumn | (ws, colIndex: number, count: number) => void | Columns deleted. | | onmoverow | (ws, from: number, to: number) => void | Row moved. | | onmovecolumn | (ws, from: number, to: number) => void | Column moved. | | onresizerow | (ws, rowIndex: number, height: number) => void | Row resized. | | onresizecolumn | (ws, colIndex: number, width: number) => void | Column resized. |

Style & Merge Events

| Event | Callback Signature | Description | | :---------- | :-------------------------------------------------------------- | :------------------ | | onstyle | (ws, x: number, y: number, style: Partial<CellStyle>) => void | Cell style changed. | | onmerge | (ws, x1, y1, x2, y2: number) => void | Cells merged. | | onunmerge | (ws, x1, y1, x2, y2: number) => void | Cells unmerged. |

Clipboard Events

| Event | Callback Signature | Description | | :-------- | :----------------------------------------------------- | :-------------------------- | | oncopy | (ws, selection: SelectionRange) => void | Data copied to clipboard. | | onpaste | (ws, x: number, y: number, data: string[][]) => void | Data pasted from clipboard. |

Formula Events

| Event | Callback Signature | Description | | :---------------- | :---------------------------------------------------- | :---------------------- | | onformulachange | (ws, x: number, y: number, formula: string) => void | A formula cell changed. |

Event Usage Example

// Listen for value changes
sheet.on('onchange', (ws, cell, x, y, value, oldValue) => {
  console.log(`[${x},${y}]: "${oldValue}" → "${value}"`);
});

// Listen for selection changes
sheet.on('onselection', (ws, x1, y1, x2, y2) => {
  console.log(`Selection: [${x1},${y1}]:[${x2},${y2}]`);
});

// Listen for edit start/end
sheet.on('oneditionstart', (ws, x, y) => {
  console.log(`Editing cell [${x},${y}]`);
});

sheet.on('oneditionend', (ws, x, y, value) => {
  console.log(`Committed [${x},${y}] = ${value}`);
});

// Remove a listener
const handler = (ws: any) => console.log('undone');
sheet.on('onundo', handler);
sheet.off('onundo', handler);

Key Types

/** Zero-based cell address */
interface CellAddress {
  x: number; // column index (0 = A)
  y: number; // row index (0 = row 1)
}

/** Inclusive selection rectangle */
interface SelectionRange {
  x1: number;
  y1: number; // top-left
  x2: number;
  y2: number; // bottom-right
}

/** Per-cell visual style */
interface CellStyle {
  bold?: boolean;
  italic?: boolean;
  underline?: boolean;
  strikethrough?: boolean;
  fontSize?: number;
  fontFamily?: string;
  color?: string; // CSS hex e.g. '#FF0000'
  backgroundColor?: string;
  align?: 'left' | 'center' | 'right';
  verticalAlign?: 'top' | 'middle' | 'bottom';
  wrap?: boolean;
  border?: BorderObject;
  numberFormat?: string; // e.g. '#,##0.00', '$#,##0'
}

/** Sheet tab configuration */
interface SheetMeta {
  worksheetName: string;
  minDimensions?: [cols: number, rows: number];
  frozenRows?: number;
  frozenCols?: number;
  hidden?: boolean;
}

Architecture Notes

| Component | File | Responsibility | | :-------------------- | :--------------------------------- | :------------------------------------------- | | SpreadsheetEngine | engine/SpreadsheetEngine.ts | Top-level public API owner | | WorksheetModel | model/Worksheet.ts | Per-sheet state | | SheetData | model/SheetData.ts | Sparse cell storage via ChunkedCellStore | | ChunkedCellStore | model/chunks/ChunkedCellStore.ts | 256×256 block cell store | | LRUCache | model/chunks/LRUCache.ts | Generic O(1) LRU eviction | | Viewport | render/viewport/Viewport.ts | Canvas renderer; dirty-tile partial repaints | | DisplayCacheManager | model/display-cache/ | LRU-bounded render cache (max 100K entries) | | CalcWorkerHost | workers/calc/CalcWorkerHost.ts | Main-thread proxy to the formula Web Worker | | SparseMetricsIndex | model/metrics/ | Fenwick-tree backed row/col offset index | | MergeIndex | model/merges/ | Row-bucketed merge lookup | | PerformanceMonitor | perf/PerformanceMonitor.ts | 6-metric rolling-window telemetry |

Invariants enforced by the architecture:

  1. No O(totalRows) or O(totalCols) work inside scroll or render handlers.
  2. Formula evaluation never happens on the paint thread.
  3. _onViewChange(x, y) triggers a partial tile repaint; _onViewChange(-1, -1) triggers a full repaint.
  4. Display cache is evicted proactively on scroll to keep memory footprint bounded.

License

Copyright © 2024-present Worksheet Systems. All rights reserved.

This software is proprietary. Usage is subject to the terms of the End-User License Agreement (EULA).

For licensing and technical support: [email protected]