@univerjs/ui
Shared application UI framework, workbench services, menus, dialogs, and Facade UI APIs for Univer.
import { UniverUIPlugin } from '@univerjs/ui'univer.registerPlugin(UniverUIPlugin, config)Entry Points
- Facade:
@univerjs/ui/facade - Locale:
@univerjs/ui/locale/*
Unit presence and undo/redo groups
The root entry exports IUnitPresenceUIAdapterRegistry, UnitPresenceUIAdapterRegistry, IUnitPresenceUIAdapter, local and remote presence-state types, IUnitPresencePoint, and UndoRedoGroupService.
Use HoverTrack with HOVER_TRACK_HOST_CLASS_NAME for themed hover tracking. preventBrowserZoomInContainers() blocks browser zoom only inside the supplied containers.
Mobile hosts can use MOBILE_UI_MODE, MobileDialogService, MobileDrawer, MobileDrawerSnap, and MobileMenu. The Facade also exposes setRibbonType() for changing between collapsed, simple, classic, and grid layouts at runtime.
Notifications
Resolve INotificationService from your plugin's injector and call show(options). It returns an IDisposable; disposing it dismisses that notification. INotificationOptions.classNames applies CSS classes to individual parts of this notification, including toast, title, description, and actionButton.
import { INotificationService } from '@univerjs/ui'const notificationService = injector.get(INotificationService)const notice = notificationService.show({ title: 'Review required', content: 'Check the latest changes before continuing.', type: 'warning', duration: Number.POSITIVE_INFINITY, closable: false, dismissible: false, action: { label: 'Dismiss', onClick: () => notice.dispose() }, classNames: { toast: 'review-notice', actionButton: 'review-notice-action', },})Define these classes in your application stylesheet. duration: Number.POSITIVE_INFINITY keeps the notice visible; closable controls the close button and dismissible controls user dismissal. Dispose any remaining notice when its owner is removed.
IUniverUIConfig
import type { DependencyOverride } from '@univerjs/core'import type { IWorkbenchOptions, MenuConfig } from '@univerjs/ui'export interface IUniverUIConfig extends IWorkbenchOptions { /** Disable auto focus when Univer bootstraps. */ disableAutoFocus?: true override?: DependencyOverride menu?: MenuConfig popupRootId?: string /** * The fallback avatar for user. */ avatarFallback?: string}MenuConfig
import type { MenuConfig, MenuItemConfig } from '@univerjs/ui'MenuConfig is a flat Record<string, MenuItemConfig> for the shared menu system used by Sheets, Docs, Slides, Boards, and PDFs. In plugin mode, pass it as menu to UniverUIPlugin. Sheets and Docs also accept it through UniverSheetsCorePreset and UniverDocsCorePreset. Use FUniver.updateMenuConfig(config) to merge changes at runtime and refresh the UI immediately. Unspecified properties retain their existing overrides or schema defaults; overrides also apply to menus registered later.
| Key | Example | Scope |
|---|---|---|
| Ribbon tab key | ribbon.insert | order among tabs. |
| Ribbon group key | ribbon.start.format | order among groups in that tab. |
| Menu item ID | sheet.command.set-range-bold | Item properties, order among siblings, and gridLayout within its Ribbon group. |
| Context-menu item ID | board.menu.duplicate-selection | Item properties and order within its context-menu group; gridLayout does not affect popup menus. |
Use RibbonPosition and the group enums, such as RibbonStartGroup, from @univerjs/ui for tab and group keys. Ribbon item IDs are available through the rendered element's data-u-command attribute. For context menus, use the item IDs defined by the product menu schema. An item ID can differ from its command ID. An item override applies wherever that item ID is used; order does not move an item into another group or tab.
MenuItemConfig
| Option | Type | Behavior |
|---|---|---|
order | number | Lower values come first among siblings. Applies to tabs, groups, and menu items. |
gridLayout | IRibbonGridLayout | Overrides the item's placement in the grid Ribbon. Omitted optional fields retain their existing values. |
hidden, disabled, activated | boolean | Overrides the menu item's display or interaction state. |
title, tooltip | string | Overrides the menu item's text or locale key. |
icon | IMenuItem['icon'] | Overrides the menu item's icon. |
type | MenuItemType | Overrides the menu item's presentation type. |
import type { MenuConfig } from '@univerjs/ui'import { UniverUIPlugin } from '@univerjs/ui'const menu: MenuConfig = { 'ribbon.insert': { order: -1 }, 'ribbon.start.format': { order: -1 }, 'sheet.command.set-range-font-family': { order: 0, gridLayout: { row: 1, column: 1, width: 160 }, },}univer.registerPlugin(UniverUIPlugin, { container: 'app', ribbonType: 'grid', menu })Product integration
Use IDs from the target product. The shared Facade methods require @univerjs/ui/facade in plugin mode, in addition to the product's own Facade entry.
| Product guide | Initial configuration | Example menu item ID | Layout scope |
|---|---|---|---|
| Sheets | UniverUIPlugin or UniverSheetsCorePreset | sheet.command.set-range-bold | Shared Ribbon and context menus. |
| Docs | UniverUIPlugin or UniverDocsCorePreset | doc.command.set-inline-format-bold | Shared Ribbon and context menus. |
| Slides | UniverUIPlugin | slide.menu.insert.text | Shared Ribbon; product Ribbon registration requires editing to be enabled. |
| Boards | UniverUIPlugin | board.menu.duplicate-selection | Shared context menus. The independent canvas toolbar uses UniverBoardsUIPlugin.toolbar.tools, not gridLayout. |
| PDFs | UniverUIPlugin | pdf.menu.tool.highlight | Shared Ribbon; product Ribbon registration requires editing to be enabled. |
Slides, Boards, and PDFs use plugin mode and do not provide core presets. Pass menu and ribbonType to the shared UI plugin, not the product UI plugin. Menu overrides do not create unregistered buttons or enable a product's disabled editor UI.
IRibbonGridLayout
import type { IRibbonGridLayout } from '@univerjs/ui'These fields only affect ribbonType: 'grid'. Coordinates start at 1 within each group, which has two rows. Explicit grid positions determine visual placement; changing order alone does not move a button with an explicit position. Avoid overlapping cells: conflicts and invalid geometry use automatic placement.
| Field | Type | Required | Behavior |
|---|---|---|---|
row | number | Yes | Row 1 or 2. |
column | number | Yes | Positive integer column index. |
rowSpan | number | No | Defaults to 1. Use 2 for a large button starting in row 1. |
columnSpan | number | No | Positive integer, defaults to 1. |
showLabel | boolean | No | Show the menu label; defaults to false. |
width | number | No | Positive, finite width in pixels. |
iconSize | number | No | Positive, finite icon size in pixels. |
When overriding an existing item, unspecified optional fields are inherited from its schema or earlier configuration. For example, changing the font selector's width retains its existing columnSpan.
IFacadeMenuItem
import type { IFacadeMenuItem, IFacadeSubmenuItem } from '@univerjs/ui/facade'Options for FUniver.createMenu(). Call appendTo() on the returned FMenu to register it.
| Option | Type | Required | Behavior |
|---|---|---|---|
id | string | Yes | Unique menu ID; also the key used by MenuConfig. |
title | string | Yes | Menu text or locale key. |
action | string or (() => void) | Yes | Command ID or callback to execute. |
icon, tooltip | string | No | Icon name and tooltip text or locale key. |
order | number | No | Display order among siblings. |
gridLayout | IRibbonGridLayout | No | Initial grid placement within the target Ribbon group. |
import '@univerjs/ui/facade'univerAPI .createMenu({ id: 'custom-action', title: 'Custom action', action: () => console.log('Custom action clicked'), order: 4, gridLayout: { row: 1, column: 3, showLabel: true, width: 96 }, }) .appendTo('ribbon.start.history')IFacadeSubmenuItem
Options for FUniver.createSubmenu(). It accepts the same id, title, icon, tooltip, order, and gridLayout options as IFacadeMenuItem, without action. gridLayout controls the submenu trigger in the Ribbon, not the popup's children. Use FSubmenu.addSubmenu() and addSeparator() to build its contents.
How is this guide?