General API
In Univer, the Facade API that can be called varies according to the different types of documents. This section will introduce the general Facade API that applies to all types of documents.
Concepts
Commands
The majority of operations in Univer are registered with the command system, and are triggered through the command system. This unified approach to operations enables Univer to readily implement features such as undo, redo, and collaboration, etc.
Commands can be simply understood as unique “events” within Univer. For more details on the design, please refer to command-system.
Commands API
Univer provides users with a unified command system, through which users can implement a variety of customized functionalities.
Each command corresponds to a unique ID. If you are looking for a specific command ID, you can refer to How to find the command ID.
Listening Commands
Univer provides two ways to listen for commands, before the command is executed and after the command is executed:
onBeforeCommandExecute
: Executes custom logic before the command is executed.onCommandExecuted
: Executes custom logic after the command is executed.
Listening Commands Before Execution
Before the command is executed, we pass a callback function to the FUniver.onBeforeCommandExecute
API to register a custom preprocessing listener.
When the command is executed, the logic inside the preprocessing listener will be executed.
const univerAPI = FUniver.newAPI(univer);
univerAPI.onBeforeCommandExecute((command) => {
const { id, type, params } = command;
// Custom logic executed before the command is executed
})
If you want to prevent the command from executing before it is executed, you can throw
an exception in the listener callback.
const univerAPI = FUniver.newAPI(univer);
univerAPI.onBeforeCommandExecute((command) => {
throw new Error('Editing is prohibited')
})
Listening Commands After Execution
After the command is executed, we can also pass a callback function to the FUniver.onCommandExecuted
API to register a custom post-processing listener.
When the command is executed, the logic inside the post-processing listener will be executed.
const univerAPI = FUniver.newAPI(univer);
univerAPI.onCommandExecuted((command) => {
const { id, type, params } = command;
// Custom logic executed after the command is executed
})
Cancel Listening
The method that registers a command listener returns an IDisposable
object, which can be destroyed by calling IDisposable.dispose
.
It is recommended that you destroy listeners that are no longer in use to help improve the robustness of your program.
const univerAPI = FUniver.newAPI(univer);
// Register a listener
const disposable = univerAPI.onBeforeCommandExecute((command) => {
// custom preprocessing logic before the command is executed
})
// Example: Destroy the listener after 1 second
setTimeout(() => {
// Destroy the listener
disposable.dispose();
}, 1000);
Execute Commands
If you already know the command ID and the parameters you need to pass, you can also execute the command using the FUniver.executeCommand
method.
For example, we can set the value of cell A1 using the sheet.command.set-range-values
command:
const univerAPI = FUniver.newAPI(univer);
// Execute the command
univerAPI.executeCommand('sheet.command.set-range-values', {
value: { v: "Hello, Univer!" },
range: { startRow: 0, startColumn: 0, endRow: 0, endColumn: 0 }
});
Events API
Univer provides a comprehensive event system that allows you to listen to and respond to various changes in the spreadsheet. Events can be broadly categorized into several groups including clipboard operations, selection changes, cell interactions, sheet modifications, and more.
Event Categories
Full event list: https://reference.univer.ai/en-US/classes/FEventName#properties
-
Clipboard Events
BeforeClipboardChange
: Triggered before clipboard content changes, can prevent change by settingparam.cancel = true
BeforeClipboardPaste
: Triggered before pasting content, can prevent paste by settingparam.cancel = true
ClipboardChanged
: Triggered after clipboard content changes, provides new clipboard contentClipboardPasted
: Triggered after content is pasted, provides pasted content
-
Selection Events
SelectionChanged
: Triggered when selection changes, provides new selection range infoSelectionMoveStart
: Triggered when selection movement begins, useful for custom selection effectsSelectionMoveEnd
: Triggered when selection movement ends, provides final selection rangeSelectionMoving
: Triggered during selection movement, useful for real-time UI updatesDragOver
: Triggered when dragging over cellsDrop
: Triggered when dropping selected content
-
Cell Events
CellClicked
: Triggered when a cell is clicked, provides cell position and content infoCellHover
: Triggered when hovering over a cell, useful for showing tooltipsCellPointerDown
: Triggered when pointer is pressed on a cell, used for starting drag or selection operationsCellPointerUp
: Triggered when pointer is released on a cell, used for completing operationsCellPointerMove
: Triggered when pointer moves over cells
-
Sheet Events
SheetValueChanged
: Triggered when sheet values change, provides changed range and new valuesSheetZoomChanged
: Triggered when zoom level changes, provides new zoom ratioSheetSkeletonChanged
: Triggered when sheet structure changes, e.g., row/column insertion/deletionBeforeSheetEditStart
: Triggered before cell editing starts, can control whether to allow editingSheetEditStarted
: Triggered when cell editing begins, useful for custom editor behaviorBeforeSheetEditEnd
: Triggered before cell editing ends, can be used for content validationSheetEditEnded
: Triggered when cell editing ends, provides edited valueSheetEditChanging
: Triggered during cell editing, useful for real-time validation or formattingScroll
: Triggered when sheet scrolls, provides scroll position infoCrosshairHighlightColorChanged
: Triggered when crosshair highlight color changesCrosshairHighlightEnabledChanged
: Triggered when crosshair highlight is enabled or disabled
-
Header Events
RowHeaderClick
: Triggered when a row header is clickedRowHeaderHover
: Triggered when hovering over a row headerColumnHeaderClick
: Triggered when a column header is clickedColumnHeaderHover
: Triggered when hovering over a column header
-
Data Validation Events
BeforeSheetDataValidationAdd
: Triggered before adding a data validation ruleSheetDataValidationChanged
: Triggered when data validation rules changeSheetDataValidatorStatusChanged
: Triggered when data validation status changes
-
Comment Events
BeforeCommentAdd
: Triggered before adding a commentCommentAdded
: Triggered after a comment is addedBeforeCommentUpdate
: Triggered before updating a commentCommentUpdated
: Triggered after a comment is updatedBeforeCommentDeleted
: Triggered before deleting a commentCommentDeleted
: Triggered after a comment is deleted
-
Data Processing Events
SheetBeforeRangeSort
: Triggered before range sortingSheetRangeSorted
: Triggered after range sortingSheetBeforeRangeFilter
: Triggered before range filteringSheetRangeFiltered
: Triggered after range filteringBeforePivotTableAdd
: Triggered before adding a pivot tablePivotTableAdded
: Triggered after a pivot table is added
Using Events
You can listen to events using the addEvent
method of the univerAPI
. Here’s the basic pattern:
univerAPI.addEvent(univerAPI.Event.EventName, (params) => {
// Handle event parameters
});
Example: Listening to Cell Clicks
univerAPI.addEvent(univerAPI.Event.CellClicked, (params) => {
const { worksheet, workbook, row, column, value } = params;
console.log(`Cell clicked at row ${row}, column ${column}`);
});
Example: Monitoring Clipboard Operations
univerAPI.addEvent(univerAPI.Event.BeforeClipboardPaste, (param) => {
const { text, html } = param;
// If you want to cancel the clipboard paste
param.cancel = true;
});
Example: Tracking Selection Changes
univerAPI.addEvent(univerAPI.Event.SelectionChanged, (params) => {
const { worksheet, workbook, selections } = params;
console.log('Selection changed:', selections);
});
Canceling Event Listeners
Event listeners return an IDisposable
object that can be used to remove the listener when it’s no longer needed:
const disposable = univerAPI.addEvent(univerAPI.Event.SheetValueChanged, (params) => {
// Handle value changes
});
// Later, when you want to remove the listener:
disposable.dispose();
Best Practices
- Always dispose of event listeners when they’re no longer needed to prevent memory leaks
- Use the appropriate event for your use case - prefer specific events over general ones
- Keep event handlers lightweight to maintain performance
- Consider using
BeforeClipboardChange
and similar “before” events when you need to prevent default behavior
undo/redo
undo
univerAPI.executeCommand('univer.command.undo')
redo
univerAPI.executeCommand('univer.command.redo')
System Clipboard
Starting from version 0.2.12
, use the FUniver.copy()
and FUniver.paste()
methods to read from and write to the system clipboard.
Copy and paste rely on the browser’s native API. When environmental conditions or permissions are insufficient, the copy and paste functions will not work. For more information, see MDN documentation .
Example: Copy and paste in a Sheet Range 0.2.12+
var sheet = univerAPI.getActiveWorkbook().getActiveSheet()
// Get A1 as the source for copying
var sourceRange = sheet.getRange(0,0)
// Set the value of A1
sourceRange.setValue('Hello, Univer!')
// Set A1 as the active selection
sheet.setActiveRange(sourceRange)
// Copy the value of A1 to the system clipboard
univerAPI.copy(sourceRange)
// Get A2 as the paste target
var targetRange = sheet.getRange(0,1)
// Set A2 as the active selection
sheet.setActiveRange(targetRange)
// Paste the clipboard content to the current selection, and the value of A2 becomes "Hello, Univer!"
univerAPI.paste()
For versions before 0.2.12
, you can use the commands-api to implement clipboard functionality:
import { CopyCommand, PasteCommand } from '@univerjs/ui';
// Copy
univerAPI.executeCommand(CopyCommand.id)
// Paste
univerAPI.executeCommand(PasteCommand.id)
Common Return Value
All of these methods return an IDisposable
object, which can be used to unsubscribe from the events when no longer needed.
UI
Please refer to the following documentation to extend the Univer UI :
WebSocket
Facade provides a convenient API createSocket
for creating a WebSocket, simply by passing in a URL. You can then listen to open, message, close, and error events, and actively send messages with the send method and actively close with the close method.
// Replace the URL with the address of your own WebSocket service
const ws = univerAPI.createSocket('ws://47.100.177.253:8449/ws')
ws.open$.subscribe(() => {
console.log('websocket opened')
ws.send('hello')
})
ws.message$.subscribe((message) => {
console.log('websocket message', message)
const content = JSON.parse(message.data).content
if (!content.includes('command')) {
return
}
const commandInfo = JSON.parse(content);
const { command, options } = commandInfo;
const { id, params } = command;
// Upon receiving collaborative data, it is locally saved
univerAPI.executeCommand(id, params, options)
});
ws.close$.subscribe(() => {
console.log("websocket closed");
});
ws.error$.subscribe((error) => {
console.log("websocket error", error);
});
univerAPI.onCommandExecuted((command, options) => {
// Only synchronize local mutations
if (command.type !== 2 || options?.fromCollab || options?.onlyLocal || command.id === 'doc.mutation.rich-text-editing') {
return;
}
const commandInfo = JSON.stringify({ command, options: { fromCollab: true } })
ws.send(commandInfo);
})
Note: Make sure there is a unitID when starting Univer. If the unitID is not specified, collaboration will not work.
Register Formula
Using Facade API, you can quickly and easily register custom formulas in the current Univer instance.
As shown in the following case, use registerFunction
to register the algorithm, name, and description required by a CUSTOMSUM
formula into the formula plugin at one time. After execution, the formula can be used. Enter =CUSTOMSUM
in any blank cell to see the prompt.
univerAPI.registerFunction({
calculate: [
[function (...variants) {
let sum = 0;
for(const variant of variants){
sum += Number(variant) || 0;
}
return sum;
}, 'CUSTOMSUM', 'Adds its arguments'],
// ... more formulas
]
})
If you need to unregister the formula, you can call the dispose
method.
const functionDisposable = univerAPI.registerFunction({
// calculate
})
// Unregister the function
functionDisposable.dispose();
If you want to provide more complete international content and description, you can also configure the locales
and description
fields. As follows.
const FUNCTION_NAMES_USER = {
USTOMSUM: 'CUSTOMSUM'
}
univerAPI.registerFunction({
locales: {
'enUS': {
formulaCustom: {
CUSTOMSUM: {
description: '将单个值、单元格引用或是区域相加,或者将三者的组合相加。',
abstract: '求参数的和',
links: [
{
title: '教学',
url: 'https://support.microsoft.com/en-US/office/sum-%E5%87%BD%E6%95%B0-043e1c7d-7726-4e80-8f32-07b23e057f89',
},
],
functionParameter: {
number1: {
name: '数值1',
detail: '要相加的第一个数字。 该数字可以是 4 之类的数字,B6 之类的单元格引用或 B2:B8 之类的单元格范围。',
},
number2: {
name: '数值2',
detail: '这是要相加的第二个数字。 可以按照这种方式最多指定 255 个数字。',
},
},
},
// ... more formulas
},
},
'enUS': {
formulaCustom: {
CUSTOMSUM: {
description: `You can add individual values, cell references or ranges or a mix of all three.`,
abstract: `Adds its arguments`,
links: [
{
title: 'Instruction',
url: 'https://support.microsoft.com/en-us/office/sum-function-043e1c7d-7726-4e80-8f32-07b23e057f89',
},
],
functionParameter: {
number1: {
name: 'number1',
detail: 'The first number you want to add. The number can be like 4, a cell reference like B6, or a cell range like B2:B8.',
},
number2: {
name: 'number2',
detail: 'This is the second number you want to add. You can specify up to 255 numbers in this way.',
},
},
},
}
}
},
description: [
{
functionName: FUNCTION_NAMES_USER.CUSTOMSUM,
aliasFunctionName: 'formulaCustom.CUSTOMSUM.aliasFunctionName',
functionType: 15,
description: 'formulaCustom.CUSTOMSUM.description',
abstract: 'formulaCustom.CUSTOMSUM.abstract',
functionParameter: [
{
name: 'formulaCustom.CUSTOMSUM.functionParameter.number1.name',
detail: 'formulaCustom.CUSTOMSUM.functionParameter.number1.detail',
example: 'A1:A20',
require: 1,
repeat: 0,
},
{
name: 'formulaCustom.CUSTOMSUM.functionParameter.number2.name',
detail: 'formulaCustom.CUSTOMSUM.functionParameter.number2.detail',
example: 'B2:B10',
require: 0,
repeat: 1,
},
],
},
// ... more formulas
],
calculate: [
[function (...variants) {
let sum = 0;
for (const variant of variants) {
sum += Number(variant) || 0;
}
return sum;
}, FUNCTION_NAMES_USER.CUSTOMSUM],
// ... more formulas
]
})
Note
- Multiple languages can be set under
locales
. For naming rules, please refer to LocaleType . Translations for multiple formulas can be added underfunctionList
. For detailed field descriptions, please refer to the How to add formulas in Formula Engine section. description
sets the description of the custom formula.calculate
writes the specific algorithm and name mapping of the calculation formula. The input parameter is the content entered by the user when using the formula, which may be a number, a string, a Boolean value, or a array.
If you want to reuse the algorithm provided by the formula system and enhance the capability of the formula algorithm, you can register a custom formula through plug-in configuration. For detailed tutorials, please refer to Custom Formula.