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

tinyweb-office-cells

v1.2.3

Published

Open-source Node.js/TypeScript library for reading, writing, and manipulating Excel XLSX files with full formatting and formula evaluation

Downloads

1,058

Readme

tinyweb-office-cells

Open-source Node.js/TypeScript library for reading, writing, and manipulating Excel XLSX files with full formatting and formula evaluation.

npm version License: MIT

Features

  • Read/Write XLSX files — full round-trip fidelity (preserves unmodified XML)
  • Cell formatting — fonts, colors, borders, fills, number formats, alignment
  • Merge cells — column widths, row heights
  • Formula evaluation — 43 built-in Excel functions
  • Data validation — dropdown lists, numeric ranges, date ranges, custom formulas
  • Conditional formatting — cell value rules, color scales, data bars, formulas
  • Named ranges — workbook and sheet-scoped defined names
  • Hyperlinks — external URLs, internal sheet references, email links
  • Comments — cell comments with author and size support
  • AutoFilter — column filters with custom, color, dynamic, and top-10 filters
  • Page breaks — horizontal and vertical page break management
  • Sheet/workbook protection — password-based protection with granular permissions
  • Document properties — title, author, subject, keywords, and custom properties
  • Page setup — orientation, paper size, margins, print area, headers/footers
  • Freeze panes — freeze rows and columns
  • Dual API naming — both camelCase and snake_case method names
  • Sheet rendering — export worksheets to HTML or PNG screenshots (via Puppeteer)
  • TypeScript-first — full type declarations included
  • Zero native dependencies — pure JavaScript, works everywhere Node.js runs

Installation

npm install tinyweb-office-cells

Quick Start

Create a Workbook and Save

import { Workbook, SaveFormat } from 'tinyweb-office-cells';

// Create a new workbook
const workbook = new Workbook();
const sheet = workbook.worksheets.get(0);

// Set cell values
sheet.cells.get('A1').putValue('Name');
sheet.cells.get('B1').putValue('Score');
sheet.cells.get('A2').putValue('Alice');
sheet.cells.get('B2').putValue(95);
sheet.cells.get('A3').putValue('Bob');
sheet.cells.get('B3').putValue(87);

// Add a formula
sheet.cells.get('B4').setFormula('=SUM(B2:B3)');

// Save to file
await workbook.save('output.xlsx');

Read an Existing File

import { Workbook } from 'tinyweb-office-cells';

const workbook = new Workbook();
await workbook.loadFile('input.xlsx');

const sheet = workbook.worksheets.get(0);
console.log(sheet.cells.get('A1').value); // Read cell value
console.log(sheet.name);                  // Sheet name

Apply Formatting

import { Workbook } from 'tinyweb-office-cells';

const workbook = new Workbook();
const sheet = workbook.worksheets.get(0);
const cell = sheet.cells.get('A1');
cell.putValue('Hello, Excel!');

// Get cell style and modify
const style = cell.getStyle();
style.font.name = 'Arial';
style.font.size = 14;
style.font.bold = true;
style.font.color = '#FF0000';
style.fill.patternType = 'solid';
style.fill.fgColor = '#FFFF00';
style.borders.top.lineStyle = 'thin';
style.borders.top.color = '#000000';
style.alignment.horizontal = 'center';
cell.setStyle(style);

await workbook.save('formatted.xlsx');

API Reference

Workbook

The main entry point for creating and manipulating Excel files.

const workbook = new Workbook();

// Load from file
await workbook.loadFile('path/to/file.xlsx');

// Load from buffer
await workbook.loadBuffer(buffer);

// Save to file
await workbook.save('output.xlsx');
await workbook.save('output.xlsx', SaveFormat.XLSX);

// Save to buffer
const buffer = await workbook.saveToBuffer(SaveFormat.XLSX);

// Access worksheets
workbook.worksheets;           // WorksheetCollection
workbook.worksheets.get(0);    // By index
workbook.worksheets.get('Sheet1'); // By name
workbook.worksheets.add('NewSheet');

// Workbook protection
workbook.properties.protection.lockStructure = true;
workbook.properties.protection.password = 'secret';

// Document properties
workbook.documentProperties.title = 'My Report';
workbook.documentProperties.author = 'John Doe';
workbook.documentProperties.subject = 'Q4 Sales';

Worksheet

Represents a single sheet in the workbook.

const sheet = workbook.worksheets.get(0);

// Properties
sheet.name = 'DataSheet';
sheet.isVisible = true;
sheet.tabColor = '#FF0000';

// Cells
sheet.cells.get('A1').putValue('Hello');

// Merge cells
sheet.cells.merge(0, 0, 2, 3); // startRow, startCol, rowCount, colCount

// Column width and row height
sheet.cells.setColumnWidth(0, 20);  // Column A = 20
sheet.cells.setRowHeight(0, 30);    // Row 1 = 30

// Freeze panes
sheet.freezePanes(1, 0);  // Freeze first row

// Page setup
sheet.pageSetup.orientation = 'landscape';
sheet.pageSetup.paperSize = 'A4';

// Sheet protection
sheet.protect('password');
sheet.protection.sheet = true;
sheet.protection.formatCells = false;

Cell / Cells

Access and manipulate individual cells.

const cells = sheet.cells;

// Get a cell (creates if not exists)
const cell = cells.get('A1');
// Also supports: cells.get(0, 0)

// Set values
cell.putValue('text');      // String
cell.putValue(42);          // Number
cell.putValue(true);        // Boolean
cell.putValue(new Date());  // Date

// Read values
cell.value;          // Raw value
cell.stringValue;    // String representation
cell.type;           // CellDataType

// Formulas
cell.setFormula('=SUM(A1:A10)');
cell.formula;        // Get formula string
cell.hasFormula();   // Check if cell has formula

// Styling
const style = cell.getStyle();
style.font.bold = true;
cell.setStyle(style);

// Comments
cell.comment = { text: 'Note', author: 'Admin' };

Style (Font, Fill, Borders, Alignment, NumberFormat)

Full cell formatting support.

const style = cell.getStyle();

// Font
style.font.name = 'Calibri';
style.font.size = 12;
style.font.bold = true;
style.font.italic = true;
style.font.underline = 'single';
style.font.strikethrough = true;
style.font.color = '#0000FF';

// Fill
style.fill.patternType = 'solid';
style.fill.fgColor = '#FFFF00';
style.fill.bgColor = '#FFFFFF';

// Borders
style.borders.top.lineStyle = 'thin';      // thin, medium, thick, dashed, dotted, double
style.borders.top.color = '#000000';
style.borders.bottom.lineStyle = 'double';
style.borders.left.lineStyle = 'medium';
style.borders.right.lineStyle = 'thin';
style.borders.diagonal.lineStyle = 'thin';

// Alignment
style.alignment.horizontal = 'center';   // left, center, right, fill, justify
style.alignment.vertical = 'center';     // top, center, bottom
style.alignment.wrapText = true;
style.alignment.textRotation = 45;
style.alignment.indent = 2;
style.alignment.shrinkToFit = true;

// Number format
style.numberFormat.formatCode = '#,##0.00';
style.numberFormat.formatCode = '0.00%';
style.numberFormat.formatCode = 'yyyy-mm-dd';
style.numberFormat.formatCode = '$#,##0.00';

// Protection
style.protection.locked = true;
style.protection.hidden = true;

cell.setStyle(style);

FormulaEvaluator

Evaluate formulas in cells.

import { FormulaEvaluator } from 'tinyweb-office-cells';

// Set up formulas
sheet.cells.get('A1').putValue(10);
sheet.cells.get('A2').putValue(20);
sheet.cells.get('A3').setFormula('=SUM(A1:A2)');

// Evaluate all formulas
const evaluator = new FormulaEvaluator(workbook);
evaluator.evaluateAll();

console.log(sheet.cells.get('A3').value); // 30

Data Validation

Add data validation rules to cells.

import { DataValidation, DataValidationType, DataValidationOperator } from 'tinyweb-office-cells';

const validations = sheet.dataValidations;

// Dropdown list
const dv = validations.add();
dv.sqref = 'A1:A10';
dv.type = DataValidationType.LIST;
dv.formula1 = '"Apple,Banana,Cherry"';

// Numeric range
const numDv = validations.add();
numDv.sqref = 'B1:B10';
numDv.type = DataValidationType.WHOLE;
numDv.operator = DataValidationOperator.BETWEEN;
numDv.formula1 = '1';
numDv.formula2 = '100';
numDv.showErrorMessage = true;
numDv.errorTitle = 'Invalid Input';
numDv.error = 'Please enter a number between 1 and 100';

Conditional Formatting

Apply conditional formatting rules.

const cfCollection = sheet.conditionalFormattings;

// Cell value rule
const cf = cfCollection.add();
cf.sqref = 'A1:A20';
cf.type = 'cellIs';
cf.operator = 'greaterThan';
cf.formula1 = '90';
cf.priority = 1;
cf.dxf = {
  font: { color: '#006100' },
  fill: { bgColor: '#C6EFCE' },
};

Hyperlinks

Add hyperlinks to cells.

const hyperlinks = sheet.hyperlinks;

// External URL
hyperlinks.add('A1', 1, 1, 'https://example.com');
const link = hyperlinks.get(0);
link.textToDisplay = 'Visit Example';
link.screenTip = 'Click to open';

// Internal reference
hyperlinks.add('A2', 1, 1, '#Sheet2!A1');

Named Ranges

Define and use named ranges.

// Add a defined name
workbook.definedNames.add('SalesData', 'Sheet1!$A$1:$D$100');
workbook.definedNames.add('TaxRate', '0.08');

// Use in formulas
sheet.cells.get('E1').setFormula('=SUM(SalesData)');

AutoFilter

Apply auto-filtering to data ranges.

const autoFilter = sheet.autoFilter;
autoFilter.range = 'A1:D100';

// Add a filter column
const fc = autoFilter.addFilterColumn(0);
fc.setValues(['Active', 'Pending']);

Comments

Add comments to cells.

const cell = sheet.cells.get('A1');
cell.comment = {
  text: 'This is a comment',
  author: 'Admin',
  width: 200,
  height: 100,
};

Page Setup

Configure print settings.

sheet.pageSetup.orientation = 'landscape';
sheet.pageSetup.paperSize = 'A4';
sheet.pageSetup.printArea = 'A1:H50';
sheet.pageSetup.fitToPagesTall = 1;
sheet.pageSetup.fitToPagesWide = 1;

Formula Support

The built-in formula evaluator supports 43 Excel functions across 7 categories:

Math & Statistics (16 functions)

SUM · AVERAGE · MIN · MAX · COUNT · COUNTA · ABS · ROUND · ROUNDUP · ROUNDDOWN · INT · MOD · POWER · SQRT · CEILING · FLOOR

String Functions (11 functions)

CONCATENATE · CONCAT · TEXT · LEN · TRIM · UPPER · LOWER · LEFT · RIGHT · MID · SUBSTITUTE · REPT

Logic Functions (4 functions)

IF · AND · OR · NOT

Lookup & Reference (4 functions)

VLOOKUP · HLOOKUP · INDEX · MATCH

Date & Time (6 functions)

TODAY · NOW · DATE · YEAR · MONTH · DAY

Information Functions (5 functions)

ISNUMBER · ISTEXT · ISBLANK · ISERROR · ISNA

Other Functions (2 functions)

VALUE · CHOOSE

Also Supports

  • Arithmetic operators: + - * / ^
  • Comparison operators: = <> < > <= >=
  • String concatenation: &
  • Cell references: A1, $A$1, Sheet1!A1
  • Range references: A1:B5
  • Defined names / named ranges
  • Nested formulas with recursive evaluation
  • Error values: #VALUE!, #REF!, #NAME?, #DIV/0!, #N/A

Examples

Create and Save a Workbook

import { Workbook } from 'tinyweb-office-cells';

const wb = new Workbook();
const ws = wb.worksheets.get(0);
ws.name = 'Sales Report';

// Headers
['Product', 'Q1', 'Q2', 'Q3', 'Q4', 'Total'].forEach((h, i) => {
  const cell = ws.cells.get(0, i);
  cell.putValue(h);
  const style = cell.getStyle();
  style.font.bold = true;
  style.fill.patternType = 'solid';
  style.fill.fgColor = '#4472C4';
  style.font.color = '#FFFFFF';
  cell.setStyle(style);
});

// Data
const data = [
  ['Widget A', 1200, 1350, 1100, 1500],
  ['Widget B', 800, 920, 870, 1050],
];

data.forEach((row, r) => {
  row.forEach((val, c) => {
    ws.cells.get(r + 1, c).putValue(val);
  });
  // Total formula
  ws.cells.get(r + 1, 5).setFormula(`=SUM(B${r + 2}:E${r + 2})`);
});

await wb.save('sales-report.xlsx');

Read and Modify an Existing File

import { Workbook } from 'tinyweb-office-cells';

const wb = new Workbook();
await wb.loadFile('existing.xlsx');

const ws = wb.worksheets.get(0);

// Read all data
for (let r = 0; r < 100; r++) {
  for (let c = 0; c < 10; c++) {
    const cell = ws.cells.get(r, c);
    if (cell.value !== null) {
      console.log(`${cell.name}: ${cell.value}`);
    }
  }
}

// Modify a cell
ws.cells.get('A1').putValue('Updated!');
await wb.save('modified.xlsx');

Data Validation with Dropdown

import { Workbook, DataValidationType } from 'tinyweb-office-cells';

const wb = new Workbook();
const ws = wb.worksheets.get(0);

ws.cells.get('A1').putValue('Select a fruit:');

const dv = ws.dataValidations.add();
dv.sqref = 'B1';
dv.type = DataValidationType.LIST;
dv.formula1 = '"Apple,Banana,Cherry,Date,Elderberry"';
dv.showDropDown = true;
dv.showInputMessage = true;
dv.inputTitle = 'Fruit Selection';
dv.inputMessage = 'Choose a fruit from the list';

await wb.save('dropdown.xlsx');

Conditional Formatting

import { Workbook } from 'tinyweb-office-cells';

const wb = new Workbook();
const ws = wb.worksheets.get(0);

// Add some scores
for (let i = 0; i < 20; i++) {
  ws.cells.get(i, 0).putValue(Math.floor(Math.random() * 100));
}

// Highlight scores above 80 in green
const cf = ws.conditionalFormattings.add();
cf.sqref = 'A1:A20';
cf.type = 'cellIs';
cf.operator = 'greaterThanOrEqual';
cf.formula1 = '80';
cf.dxf = {
  fill: { bgColor: '#C6EFCE' },
  font: { color: '#006100' },
};

await wb.save('conditional.xlsx');

Render Worksheet to HTML / PNG

Convert any worksheet to an HTML table with full styling, or capture a PNG screenshot.

import { Workbook, worksheetToHtml, worksheetToPng } from 'tinyweb-office-cells';

const wb = new Workbook();
await wb.loadFile('report.xlsx');
const ws = wb.worksheets.get(0);

// Render to HTML string (with inline styles for fonts, fills, borders, merges)
const html = worksheetToHtml(ws);
// Or as a full HTML page:
const fullHtml = worksheetToHtml(ws, { fullPage: true });

// Render only a specific range:
const rangeHtml = worksheetToHtml(ws, { range: 'A1:D10' });
const rangePng = await worksheetToPng(ws, { range: 'B2:F20' });

// Render to PNG (requires puppeteer as peer dependency)
// npm install puppeteer
const pngBuffer = await worksheetToPng(ws);
fs.writeFileSync('sheet.png', pngBuffer);

// Also available as convenience methods on Worksheet:
const html2 = ws.toHtml();
const png2 = await ws.toPng();

Render options:

| Option | Type | Default | Description | |---|---|---|---| | fullPage | boolean | false | Wrap table in a full HTML document | | defaultFont | string | 'Calibri,Arial,sans-serif' | Default font family | | range | string | — | Render only cells within this A1 range, e.g. 'A1:D10' | | viewportWidth | number | 1200 | Viewport width for PNG rendering |

Note: PNG rendering requires puppeteer as an optional peer dependency. Install it separately: npm install puppeteer

API Compatibility

This library provides dual naming conventions for maximum compatibility:

| camelCase (TypeScript) | snake_case (Python-compat) | |---|---| | cell.putValue(v) | cell.put_value(v) | | cell.getStyle() | cell.get_style() | | cell.setStyle(s) | cell.set_style(s) | | cell.hasFormula() | cell.has_formula() | | cell.setFormula(f) | cell.set_formula(f) | | cell.stringValue | cell.string_value | | cells.setColumnWidth() | cells.set_column_width() | | cells.setRowHeight() | cells.set_row_height() | | workbook.loadFile() | workbook.load_file() | | workbook.saveToBuffer() | workbook.save_to_buffer() |

Both naming styles work identically — use whichever fits your codebase.

TypeScript

Full TypeScript declarations are included. All classes, interfaces, enums, and types are exported:

import {
  Workbook,
  Worksheet,
  Cell,
  Cells,
  Style,
  Font,
  Fill,
  Border,
  Borders,
  Alignment,
  NumberFormat,
  Protection,
  SaveFormat,
  FormulaEvaluator,
  DataValidation,
  DataValidationCollection,
  DataValidationType,
  DataValidationOperator,
  ConditionalFormat,
  ConditionalFormatCollection,
  Hyperlink,
  HyperlinkCollection,
  AutoFilter,
  FilterColumn,
  DefinedName,
  DefinedNameCollection,
  HorizontalPageBreakCollection,
  VerticalPageBreakCollection,
  SheetProtection,
  PageSetup,
  FreezePane,
  WorkbookProtection,
  DocumentProperties,
  // Rendering
  worksheetToHtml,
  worksheetToPng,
} from 'tinyweb-office-cells';

Dependencies

| Package | Purpose | |---|---| | jszip | XLSX ZIP container read/write | | fast-xml-parser | XML parsing and generation | | puppeteer (optional) | PNG screenshot rendering (only needed for worksheetToPng) |

No native/binary dependencies — works on any platform where Node.js runs.

License

MIT