Composants personnalisés

Web SDK propose plusieurs méthodes pour intégrer des composants personnalisés afin d’étendre et d’adapter ses fonctionnalités. Ce guide présente plusieurs méthodes courantes.

Univer ne transmet pas directement les composants en tant que paramètres aux fonctions de rendu. Vous devez d’abord les enregistrer auprès d’Univer à l’aide de la Facade API avant de pouvoir les utiliser dans les différents points de montage.

Si vous ne savez pas comment obtenir une instance de la Facade API, consultez la page Facade API.

Enregistrer des composants personnalisés

TypeScript
univerAPI.registerComponent(componentKey, CustomComponent, options)

Utilisez la méthode univerAPI.registerComponent pour enregistrer des composants personnalisés. Cette méthode accepte trois paramètres :

  • componentKey : identifiant unique du composant, utilisé pour le référencer dans Univer.
  • CustomComponent : implémentation du composant, qui peut être un composant React, Vue ou Web Component.
  • options : options de configuration facultatives permettant notamment d’indiquer le framework dont dépend le composant.

Composants React

L’enregistrement d’un composant React ne nécessite aucune configuration supplémentaire ; assurez-vous simplement qu’il s’agit d’un composant React valide. Voici un exemple simple :

TSX
function ReactComponent(props: Record<string, any>) {  return <div>Hello Univer!</div>}univerAPI.registerComponent('MyReactComponent', ReactComponent)

Composants Vue

Vue 3.x

Pour enregistrer des composants Vue, installez et enregistrez le plugin UniverVue3AdapterPlugin du package @univerjs/ui-adapter-vue3 :

Shell
pnpm add @univerjs/ui-adapter-vue3
TypeScript
import { UniverVue3AdapterPlugin } from '@univerjs/ui-adapter-vue3'univer.registerPlugin(UniverVue3AdapterPlugin)

Lors de l’enregistrement de composants Vue, vous devez définir l’option framework sur 'vue3' :

TSX
const Vue3Component = defineComponent({  setup(props) {    return () => <div>Hello Univer!</div>  },})univerAPI.registerComponent('MyVue3Component', Vue3Component, {  framework: 'vue3',})

Vue 2.x

Comme Vue 2.x est arrivé en fin de vie et n’est plus maintenu, Univer ne fournit actuellement aucun plugin d’adaptation d’interface utilisateur pour Vue 2.x. Vous pouvez toutefois créer un plugin personnalisé afin d’implémenter votre propre adaptateur Vue 2.x. Voici un exemple :

TypeScript
import { DependentOn, Inject, Injector, Plugin } from '@univerjs/core'import { ComponentManager, UniverUIPlugin } from '@univerjs/ui'import Vue from 'vue'/** * The plugin that allows Univer to use Vue 2 components as UI components. */@DependentOn(UniverUIPlugin)export class UniverVue2AdapterPlugin extends Plugin {  static override pluginName = 'UNIVER_UI_VUE2_ADAPTER_PLUGIN'  constructor(    private readonly _config = {},    @Inject(Injector) protected readonly _injector: Injector,    @Inject(ComponentManager) protected readonly _componentManager: ComponentManager,  ) {    super()  }  override onStarting(): void {    const { createElement, useEffect, useRef } = this._componentManager.reactUtils    this._componentManager.setHandler('vue2', (component: any) => {      return (props: Record<string, any>) =>        createElement(VueComponentWrapper, {          component,          props: Object.keys(props).reduce<Record<string, any>>((acc, key) => {            if (key !== 'key') {              acc[key] = props[key]            }            return acc          }, {}),          reactUtils: { createElement, useEffect, useRef },        })    })  }}export function VueComponentWrapper(options: {  component: any  props: Record<string, any>  reactUtils: typeof ComponentManager.prototype.reactUtils}) {  const { component, props, reactUtils } = options  const { createElement, useEffect, useRef } = reactUtils  const domRef = useRef<HTMLDivElement>(null)  useEffect(() => {    if (!domRef.current) return    const Constructor = Vue.extend(component)    const instance = new Constructor({      data: props,    })    instance.$mount()    domRef.current.appendChild(instance.$el)    return () => {      instance.$destroy()    }  }, [props])  return createElement('div', { ref: domRef })}

Enregistrez-le ensuite :

TypeScript
import { UniverVue2AdapterPlugin } from './ui-adapter-vue2'univer.registerPlugin(UniverUIPlugin)univer.registerPlugin(UniverVue2AdapterPlugin)

Lors de l’enregistrement de composants Vue 2.x, vous devez définir l’option framework sur 'vue2' :

TSX
const Vue2Component = Vue.component('MyVue2Component', {  template: '<div>Hello, Univer!</div>',})univerAPI.registerComponent('MyVue2Component', Vue2Component, {  framework: 'vue2',})

Web Components

Pour enregistrer des Web Components, assurez-vous qu’ils respectent le standard Web Components, puis installez et enregistrez le plugin UniverWebComponentAdapterPlugin du package @univerjs/ui-adapter-web-component :

Shell
pnpm add @univerjs/ui-adapter-web-component
TypeScript
import { UniverWebComponentAdapterPlugin } from '@univerjs/ui-adapter-web-component'univer.registerPlugin(UniverWebComponentAdapterPlugin)

Lors de l’enregistrement de Web Components, vous devez définir l’option framework sur 'web-component' :

TSX
class WebComponent extends HTMLElement {  constructor() {    super()    const shadow = this.attachShadow({ mode: 'open' })    const div = document.createElement('div')    div.textContent = 'Hello Univer!'    shadow.appendChild(div)  }}univerAPI.registerComponent('my-web-component', WebComponent, {  framework: 'web-component',})

Angular

Convertissez un composant Angular en élément personnalisé avec createCustomElement de @angular/elements, puis enregistrez-le avec l’adaptateur Web Component de Univer. Il pourra apparaître dans une barre latérale ou un dialogue.

Ajoutez @angular/elements à la même version que @angular/core, et @univerjs/ui-adapter-web-component à la même version que les autres packages Univer.

Appelez cette fonction après l’initialisation de Univer. Dans le composant hôte, obtenez l’injecteur avec private readonly injector = inject(Injector), puis appelez registerAngularPanel(univer, univerAPI, this.injector). Importez inject et Injector depuis @angular/core dans ce composant.

TypeScript
import type { Injector } from '@angular/core'import type { FUniver, Univer } from '@univerjs/presets'import { Component } from '@angular/core'import { createCustomElement } from '@angular/elements'import { UniverWebComponentAdapterPlugin } from '@univerjs/ui-adapter-web-component'@Component({  selector: 'app-angular-panel',  standalone: true,  template: '<p>Hello from Angular!</p>',})export class AngularPanelComponent {}export function registerAngularPanel(univer: Univer, univerAPI: FUniver, injector: Injector) {  const element = createCustomElement(AngularPanelComponent, { injector })  univer.registerPlugin(UniverWebComponentAdapterPlugin)  return univerAPI.registerComponent('univer-angular-panel', element, {    framework: 'web-component',  })}

Une fois l’éditeur rendu, utilisez la clé enregistrée comme contenu de la barre latérale :

TypeScript
const sidebar = univerAPI.openSidebar({  header: { title: 'Angular' },  children: { label: 'univer-angular-panel' },  width: 360,})

Conservez les handles d’enregistrement et de barre latérale, puis appelez leur méthode dispose() quand ils ne sont plus nécessaires. Enregistrez l’élément une seule fois dans l’application. Son nom doit contenir un trait d’union et différer du selector Angular.

Angular Elements convertit les entrées en propriétés et les sorties en événements DOM CustomEvent. L’adaptateur Univer transmet les propriétés sans s’abonner automatiquement aux sorties Angular : reliez explicitement les événements nécessaires.

Utiliser des composants personnalisés

Les méthodes suivantes vous permettent d’intégrer avec souplesse différents composants personnalisés dans Univer afin d’enrichir et d’adapter ses fonctionnalités.

Attention

  1. Avant d’utiliser ces méthodes, assurez-vous qu’Univer a terminé le rendu. 2. Pour les composants qui doivent être enregistrés, vérifiez que leur enregistrement a bien été effectué avant de les utiliser. 3. Utilisez la méthode dispose() pour nettoyer et supprimer les composants ajoutés afin d’éviter les fuites de mémoire.

Ajouter des éléments de menu personnalisés

La barre de menu supérieure (Ribbon) et le menu contextuel (Context Menu) peuvent tous deux contenir des composants personnalisés. Pour ajouter ces composants à des éléments de menu, vous devez créer un plugin personnalisé. Nous avons préparé un guide de bonnes pratiques pour l’ajout d’éléments de menu personnalisés afin de vous aider à démarrer rapidement.

Remplacer des composants intégrés

Avertissement

Le remplacement de composants intégrés peut empêcher certaines fonctionnalités de fonctionner correctement. Lisez attentivement le code source et la documentation avant de tenter de remplacer des composants, et procédez avec prudence.

univerAPI.registerComponent enregistre une substitution par défaut (override: true). Elle est prioritaire, quel que soit l’ordre d’enregistrement du composant par défaut du plugin. Une seule substitution peut être active par componentKey : libérez la précédente avant d’en enregistrer une autre. La méthode dispose() de l’objet retourné rétablit le composant par défaut, s’il est enregistré. Utilisez { override: false } pour enregistrer un composant par défaut.

Enregistrez la substitution avant la première ouverture de la vue. Modifier l’enregistrement ne déclenche pas automatiquement un nouveau rendu des vues déjà montées.

Les entrées publiques des packages Sheets exposent ces clés pour remplacer les composants intégrés correspondants :

ComposantClé exportéePackage
Noms définisDEFINED_NAME_CONTAINER@univerjs/sheets-ui
Autres fonctionsMORE_FUNCTIONS_COMPONENT@univerjs/sheets-formula-ui
Validation des donnéesDATA_VALIDATION_PANEL@univerjs/sheets-data-validation-ui
Mise en forme conditionnelleCF_PANEL_KEY@univerjs/sheets-conditional-formatting-ui

Par exemple, pour remplacer simplement le composant ColorPicker intégré :

TSX
// Following code only replaces the UI of the built-in ColorPicker component, not its functionalityuniverAPI.registerComponent('UI_COLOR_PICKER_COMPONENT', () => <input type="color" />)

Utiliser des composants comme contenu

Dans la barre latérale

La méthode univerAPI.openSidebar permet d’ouvrir dans l’interface d’Univer une barre latérale contenant un composant personnalisé.

TSX
// You should register the component at an appropriate time (e.g., after Univer has loaded)univerAPI.registerComponent('MyCustomSidebarComponent', () => <div>Hello Univer!</div>)const sidebar = univerAPI.openSidebar({  header: { title: 'My Sidebar' },  children: { label: 'MyCustomSidebarComponent' },  onClose: () => {    console.log('close')  },  width: 360,})// Later close the sidebarsidebar.dispose()

Référence : univerAPI.openSidebar

Dans une boîte de dialogue

La méthode univerAPI.openDialog permet d’ouvrir une boîte de dialogue contenant un composant personnalisé.

TSX
// You should register the component at an appropriate time (e.g., after Univer has loaded)univerAPI.registerComponent('MyCustomDialogComponent', () => <div>Hello Univer!</div>)const dialog = univerAPI.openDialog({  id: 'unique-dialog-id', // The unique identifier for the dialog  draggable: true,  width: 300,  title: { title: 'My Dialog' },  children: {    label: 'MyCustomDialogComponent',  },  destroyOnClose: true,  preservePositionOnDestroy: true,  onClose: () => {},})// Later close the dialogdialog.dispose()

Référence : univerAPI.openDialog

Associer une fenêtre contextuelle à des cellules

La méthode FRange.attachPopup permet d’associer une fenêtre contextuelle personnalisée à une plage de cellules donnée.

  • Une fenêtre contextuelle est un élément DOM temporaire associé à une cellule. Elle sert généralement à afficher des informations d’état provisoires et ne prend pas en charge le stockage persistant.
  • La méthode FRange.attachPopup(popup: IFCanvasPopup) permet d’associer une fenêtre contextuelle personnalisée à une plage de cellules donnée.
  • La fenêtre contextuelle se fixe sur les bords de la cellule et ajuste automatiquement sa position et son orientation si elle est masquée.
TSX
// You should register the component at an appropriate time (e.g., after Univer has loaded)univerAPI.registerComponent('MyCustomPopupComponent', () => <div>Hello Univer!</div>)const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:J10')// Attach the popup to the first cell of the range// If `disposable` is null, it indicates that the popup was not added successfullyconst disposable = fRange.attachPopup({  componentKey: 'MyCustomPopupComponent',})// Remove the popupdisposable.dispose()

Associer une fenêtre contextuelle d’alerte

La méthode FRange.attachAlertPopup permet d’associer une fenêtre contextuelle d’alerte à la cellule de départ d’une plage donnée.

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')const disposable = fRange.attachAlertPopup({  key: 'unique-alert-key', // Unique identifier  title: '这是一个警告!',  message: '这是一个警告!',  width: 300,  height: 200,  // 0: Information  // 1: Warning  // 2: Error  type: 0,})// Remove the alert laterdisposable.dispose()

Ajouter un DOM flottant à une feuille de calcul

La méthode FWorksheet.addFloatDomToPosition permet d’ajouter un DOM flottant à une feuille de calcul.

  • Avant d’utiliser cette méthode, vous devez installer le plugin @univerjs/sheets-drawing-ui ou le preset @univerjs/preset-sheets-drawing.
  • Le DOM flottant est un composant déplaçable qui s’affiche au-dessus de la feuille de calcul et prend en charge le stockage persistant.
  • Vous devez appeler cette méthode une fois le rendu d’Univer terminé.
  • componentKey : identifiant unique du composant, utilisé pour y faire référence dans Univer.
  • Définition complète des paramètres
TSX
// You should register the component at an appropriate time (e.g., after Univer has loaded)univerAPI.registerComponent('MyCustomFloatDOMComponent', ({ data }) => (  <div>    Hello    {data?.label}!  </div>))const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// Add a floating DOM to the worksheet// If `disposable` is null, it indicates that the floating DOM was not added successfullyconst disposable = fWorksheet.addFloatDomToPosition({  componentKey: 'MyCustomFloatDOMComponent',  initPosition: {    startX: 100,    endX: 200,    startY: 100,    endY: 200,  },  // The data for the component  data: {    label: 'Univer',  },})// Remove the floating DOMdisposable.dispose()

Que pensez-vous de ce guide ?

© 2026 DreamNum Co., Ltd.