| name | univer |
| description | Build spreadsheet applications using Univer, a TypeScript spreadsheet library. Use for rendering spreadsheets, handling cell data, managing images/drawings, data validation, conditional formatting, and spreadsheet events. Use when this capability is needed. |
| metadata | {"author":"dreamtides"} |
Univer Spreadsheet Library
Build web-based spreadsheet applications using Univer's Facade API.
Official Resources
Quick Start
import { createUniver, defaultTheme, LocaleType } from '@univerjs/presets';
import { UniverSheetsCorePreset } from '@univerjs/presets/preset-sheets-core';
import '@univerjs/presets/lib/styles/preset-sheets-core.css';
const { univer, univerAPI } = createUniver({
locale: LocaleType.EN_US,
theme: defaultTheme,
presets: [UniverSheetsCorePreset()],
});
const workbook = univerAPI.createWorkbook({ name: 'My Workbook' });
Core Concepts
Getting References
const fWorkbook = univerAPI.getActiveWorkbook();
const fWorksheet = fWorkbook.getActiveSheet();
const fRange = fWorksheet.getRange('A1:B10');
const fRange2 = fWorksheet.getRange(0, 0, 10, 2);
Cell Values
const value = fRange.getValue();
fRange.setValueForCell(42);
const values = fRange.getValues();
fRange.setValues([
['A1', 'B1'],
['A2', 'B2'],
]);
Cell Styling
fRange.setBackgroundColor('#FFFF00');
fRange.setFontWeight('bold');
fRange.setFontColor('#FF0000');
fRange.setFontSize(14);
fRange.setHorizontalAlignment('center');
fRange.setVerticalAlignment('middle');
fRange.setTextWrap(true);
const style = fRange.getCellStyleData();
Row and Column Operations
fWorksheet.insertRowBefore(5);
fWorksheet.insertRowAfter(5);
fWorksheet.deleteRow(5);
fWorksheet.setRowHeight(5, 100);
fWorksheet.setColumnWidth(0, 150);
fWorksheet.hideRow(5);
fWorksheet.showRow(5);
Sheet Operations
const newSheet = fWorkbook.insertSheet();
fWorkbook.deleteSheet(sheet.getSheetId());
fWorksheet.setName('New Name');
fWorkbook.setActiveSheet(fWorksheet);
const sheetId = fWorksheet.getSheetId();
const sheetName = fWorksheet.getSheetName();
Events
univerAPI.addEvent(univerAPI.Event.SheetValueChanged, (params) => {
const { effectedRanges, payload } = params;
console.log('Values changed:', effectedRanges);
});
univerAPI.addEvent(univerAPI.Event.ActiveSheetChanged, (params) => {
const { workbook, activeSheet } = params;
});
univerAPI.addEvent(univerAPI.Event.BeforeSheetCreate, (params) => {
params.cancel = true;
});
const disposable = univerAPI.addEvent(...);
disposable.dispose();
Available Events
SheetValueChanged - Cell values changed
SheetCreated / BeforeSheetCreate - Sheet creation
SheetDeleted / BeforeSheetDelete - Sheet deletion
ActiveSheetChanged / BeforeActiveSheetChange - Sheet activation
SheetMoved / BeforeSheetMove - Sheet reordering
SheetNameChanged / BeforeSheetNameChange - Sheet rename
WorkbookCreated / WorkbookDisposed - Workbook lifecycle
Images / Drawings
Required Packages
pnpm add @univerjs/drawing @univerjs/drawing-ui @univerjs/sheets-drawing @univerjs/sheets-drawing-ui
Import Facade Extension
import '@univerjs/sheets-drawing-ui/facade';
Insert Floating Images
await fWorksheet.insertImage(url, 5, 5);
await fWorksheet.insertImage(url, 5, 5, 10, 10);
const image = await fWorksheet.newOverGridImage()
.setSource(url, univerAPI.Enum.ImageSourceType.URL)
.setColumn(5)
.setRow(5)
.setWidth(200)
.setHeight(150)
.setColumnOffset(10)
.setRowOffset(10)
.setRotate(0)
.setAnchorType(univerAPI.Enum.SheetDrawingAnchorType.Position)
.buildAsync();
fWorksheet.insertImages([image]);
Image Sources
.setSource('https://example.com/image.png', univerAPI.Enum.ImageSourceType.URL)
.setSource('data:image/png;base64,iVBORw0...', univerAPI.Enum.ImageSourceType.BASE64)
Tauri Asset Protocol (for local files)
import { convertFileSrc } from '@tauri-apps/api/core';
const localPath = '/path/to/cached/image.png';
const assetUrl = convertFileSrc(localPath);
await fWorksheet.insertImage(assetUrl, column, row);
Required tauri.conf.json:
{
"app": {
"security": {
"csp": "default-src 'self' ipc: http://ipc.localhost; img-src 'self' asset: http://asset.localhost",
"assetProtocol": {
"enable": true,
"scope": {
"requireLiteralLeadingDot": false,
"allow": ["$APPDATA/**/*", "$CACHE/**/*"]
}
}
}
}
}
Manage Images
const images = fWorksheet.getImages();
const image = fWorksheet.getImageById('drawingId');
const updatedImage = await image.toBuilder()
.setWidth(100)
.setHeight(50)
.buildAsync();
fWorksheet.updateImages([updatedImage]);
image.remove();
image.setFront();
image.setBack();
image.setForward();
image.setBackward();
Image Events
univerAPI.addEvent(univerAPI.Event.OverGridImageInserted, (params) => {
const { workbook, images } = params;
});
univerAPI.addEvent(univerAPI.Event.BeforeOverGridImageInsert, (params) => {
params.cancel = true;
});
Data Validation
Create Validation Rules
const rule = univerAPI.newDataValidation()
.requireValueInList(['Yes', 'No', 'Maybe'])
.setOptions({
allowBlank: true,
showErrorMessage: true,
error: 'Please select a valid option'
})
.build();
fRange.setDataValidation(rule);
const sourceRange = fWorksheet.getRange('Z1:Z10');
const rule = univerAPI.newDataValidation()
.requireValueInRange(sourceRange)
.build();
const rule = univerAPI.newDataValidation()
.requireCheckbox('Yes', 'No')
.build();
const rule = univerAPI.newDataValidation()
.requireNumberBetween(1, 100)
.build();
const rule = univerAPI.newDataValidation()
.requireDateBetween(new Date('2024-01-01'), new Date())
.();
rule = univerAPI.()
.()
.();
Validation Methods
requireValueInList(values[], multiple?, showDropdown?) - Dropdown
requireValueInRange(fRange, multiple?, showDropdown?) - Range reference
requireCheckbox(checked?, unchecked?) - Checkbox
requireNumberBetween(start, end, isInteger?) - Number range
requireNumberGreaterThan(num, isInteger?) - Minimum
requireNumberLessThan(num, isInteger?) - Maximum
requireNumberEqualTo(num, isInteger?) - Exact match
requireDateBetween(start, end) - Date range
requireDateAfter(date) / requireDateBefore(date)
requireFormulaSatisfied(formula) - Custom formula
Get Validation Status
const status = await fRange.getValidatorStatus();
Conditional Formatting
const rule = fWorksheet.newConditionalFormattingRule()
.whenCellEmpty()
.setBackground('#FF0000')
.setRanges([fRange.getRange()])
.build();
fWorksheet.addConditionalFormattingRule(rule);
.whenCellEmpty()
.whenCellNotEmpty()
.whenTextContains('text')
.whenTextStartsWith('prefix')
.whenNumberGreaterThan(10)
.whenNumberBetween(1, 100)
.whenDateBefore(new Date())
.setAverage(operator)
.setBackground('#FF0000')
.setFontColor('#FFFFFF')
.setBold(true)
.setItalic(true)
Freezing Panes
fWorksheet.setFreeze({ row: 1, column: 1 });
fWorksheet.cancelFreeze();
Merge Cells
fRange.merge();
fRange.unmerge();
const isMerged = fRange.isMerged();
Selection
const selection = fWorksheet.getSelection();
const activeCell = selection.getActiveCell();
const activeRange = selection.getActiveRange();
fWorksheet.setActiveRange(fRange);
Workbook Data Structure
const workbookData = {
id: 'workbook-id',
name: 'My Workbook',
sheets: {
'sheet-id': {
id: 'sheet-id',
name: 'Sheet1',
rowCount: 1000,
columnCount: 26,
cellData: {
0: {
0: { v: 'A1 value', s: 'style-id' },
1: { v: 'B1 value' }
}
}
}
},
sheetOrder: ['sheet-id']
};
const cellData = {
v: 'cell value',
s: 'style-id',
t: 1,
p: { }
};
univerAPI.createWorkbook(workbookData);
Enums
univerAPI.Enum.ImageSourceType.URL
univerAPI.Enum.ImageSourceType.BASE64
univerAPI.Enum.SheetDrawingAnchorType.Position
univerAPI.Enum.SheetDrawingAnchorType.Both
univerAPI.Enum.SheetDrawingAnchorType.None
univerAPI.Enum.DataValidationType.LIST
univerAPI.Enum.DataValidationType.CHECKBOX
univerAPI.Enum.DataValidationType.DECIMAL
React Integration
import { useEffect, useRef } from 'react';
function Spreadsheet() {
const containerRef = useRef<HTMLDivElement>(null);
const univerRef = useRef<{ univer: any; univerAPI: any } | null>(null);
useEffect(() => {
if (containerRef.current && !univerRef.current) {
const { univer, univerAPI } = createUniver({
locale: LocaleType.EN_US,
theme: defaultTheme,
presets: [UniverSheetsCorePreset({ container: containerRef.current })],
});
univerRef.current = { univer, univerAPI };
univerAPI.createWorkbook({});
}
return () => {
univerRef.current?.univer.dispose();
univerRef.current = null;
};
}, []);
return <div ref={containerRef} style={{ width: '100%', height: '%' }} />;
}
Cleanup
const disposable = univerAPI.addEvent(...);
disposable.dispose();
univer.dispose();
Plugin Configuration
Required plugins loaded in order:
- UniverRenderEnginePlugin - Canvas rendering
- UniverFormulaEnginePlugin - Formula engine
- UniverUIPlugin - UI framework
- UniverDocsPlugin - Text content
- UniverSheetsPlugin - Core spreadsheet
- UniverSheetsUIPlugin - Spreadsheet UI
- UniverSheetsFormulaPlugin - Formula support
- UniverSheetsFilterPlugin - Filtering
- UniverSheetsSortPlugin - Sorting
- UniverDataValidationPlugin - Validation
- UniverSheetsConditionalFormattingPlugin - Conditional formatting
- UniverSheetsDrawingPlugin - Images/drawings
Or use presets for simplified setup.
Documentation Source
Univer source code available at: ~/Desktop/tmp/univer/
- packages/core/src/facade/ - Core Facade API
- packages/sheets/src/facade/ - Sheets Facade API
- packages/sheets-drawing-ui/src/facade/ - Image/drawing APIs
- packages/sheets-data-validation/src/facade/ - Data validation
- packages/sheets-conditional-formatting/src/facade/ - Conditional formatting
Converted and distributed by TomeVault — claim your Tome and manage your conversions.