사용자 지정 컴포넌트

Web SDK는 사용자 지정 컴포넌트를 통합하는 여러 방법을 제공하므로 기능을 확장하고 원하는 대로 조정할 수 있습니다. 이 가이드에서는 자주 사용하는 몇 가지 방법을 소개합니다.

Univer는 컴포넌트를 렌더링 함수에 매개변수로 직접 전달하지 않습니다. 여러 마운트 지점에서 컴포넌트를 사용하려면 먼저 Facade API를 통해 Univer에 등록해야 합니다.

Facade API 인스턴스를 가져오는 방법이 익숙하지 않다면 Facade API를 참고하세요.

사용자 지정 컴포넌트 등록

TypeScript
univerAPI.registerComponent(componentKey, CustomComponent, options)

univerAPI.registerComponent 메서드를 사용해 사용자 지정 컴포넌트를 등록할 수 있습니다. 이 메서드는 세 가지 매개변수를 받습니다.

  • componentKey: Univer에서 컴포넌트를 참조할 때 사용하는 고유 식별자입니다.
  • CustomComponent: 컴포넌트 구현입니다. React, Vue 또는 Web Component를 사용할 수 있습니다.
  • options: 컴포넌트가 의존하는 프레임워크나 그 밖의 관련 설정을 지정하는 선택적 구성 옵션입니다.

React 컴포넌트

React 컴포넌트를 등록할 때는 별도의 구성이 필요하지 않습니다. 유효한 React 컴포넌트인지 확인하기만 하면 됩니다. 다음은 간단한 예입니다.

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

Vue 컴포넌트

Vue 3.x

Vue 컴포넌트를 등록하려면 UniverVue3AdapterPlugin을 @univerjs/ui-adapter-vue3 패키지에서 설치하고 등록해야 합니다.

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

Vue 컴포넌트를 등록할 때는 framework 옵션을 'vue3'으로 지정해야 합니다.

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

Vue 2.x

Vue 2.x는 지원 종료(EOL)되어 더 이상 유지 관리되지 않으므로 Univer는 현재 Vue 2.x용 UI 어댑터 플러그인을 제공하지 않습니다. 하지만 사용자 지정 플러그인을 만들어 Vue 2.x 어댑터를 구현할 수 있습니다. 다음은 Vue 2.x 어댑터 플러그인을 만드는 예입니다.

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 })}

그런 다음 플러그인을 등록합니다.

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

Vue 2.x 컴포넌트를 등록할 때는 framework 옵션을 'vue2'로 지정해야 합니다.

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

Web Components

Web Components를 등록하려면 컴포넌트가 Web Components 표준을 준수하는지 확인하고, UniverWebComponentAdapterPlugin을 @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)

Web Components를 등록할 때는 framework 옵션을 '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

@angular/elements의 createCustomElement로 Angular 컴포넌트를 사용자 정의 요소로 변환한 후 Univer의 Web Component 어댑터에 등록하세요. Angular 컴포넌트를 Univer 사이드바나 대화 상자에서 사용할 수 있습니다.

@angular/core와 같은 버전의 @angular/elements, 다른 Univer 패키지와 같은 버전의 @univerjs/ui-adapter-web-component를 추가하세요.

Univer 초기화 후 아래 함수를 호출하세요. 호스트 컴포넌트에서 private readonly injector = inject(Injector)로 Angular 주입기를 가져와 registerAngularPanel(univer, univerAPI, this.injector)에 전달합니다. 호스트의 inject와 Injector는 @angular/core에서 가져오세요.

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',  })}

편집기 렌더링 후 등록한 키를 사이드바 콘텐츠로 사용하세요.

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

반환된 등록 핸들과 사이드바 핸들을 보관하고 더 이상 필요하지 않으면 각각 dispose()를 호출하세요. 사용자 정의 요소는 애플리케이션에서 한 번만 등록합니다. 이름에 하이픈이 있어야 하며 Angular 컴포넌트의 selector와 달라야 합니다.

Angular Elements는 입력을 요소 속성으로, 출력을 DOM CustomEvent로 변환합니다. Univer 어댑터는 속성을 전달하지만 Angular 출력을 자동 구독하지 않습니다. 필요한 이벤트를 명시적으로 연결하세요.

사용자 지정 컴포넌트 사용

다음 메서드를 사용하면 다양한 사용자 지정 컴포넌트를 Univer에 유연하게 통합하여 기능을 확장하고 맞춤 설정할 수 있습니다.

주의

  1. 이 메서드를 사용하기 전에 Univer의 렌더링이 완료되었는지 확인하세요. 2. 등록이 필요한 컴포넌트는 사용하기 전에 올바르게 등록되었는지 확인하세요. 3. 메모리 누수를 방지하려면 dispose() 메서드로 추가한 컴포넌트를 정리하고 제거하세요.

사용자 지정 메뉴 항목 추가

상단 메뉴 모음(Ribbon)과 오른쪽 클릭 메뉴(Context Menu) 모두에 사용자 지정 컴포넌트를 넣을 수 있습니다. 메뉴 항목에 사용자 지정 컴포넌트를 추가하려면 사용자 지정 플러그인을 만들어야 합니다. 빠르게 시작할 수 있도록 사용자 지정 메뉴 항목 추가 모범 사례를 준비했습니다.

기본 제공 컴포넌트 교체

경고

기본 제공 컴포넌트를 교체하면 일부 기능이 제대로 작동하지 않을 수 있습니다. 컴포넌트를 교체하기 전에 소스 코드와 문서를 충분히 읽고 신중하게 진행하세요.

univerAPI.registerComponent는 기본적으로 재정의 컴포넌트를 등록합니다(override: true). 플러그인이 기본 컴포넌트를 등록하는 순서와 관계없이 재정의가 우선합니다. 각 componentKey에는 하나의 재정의만 활성화할 수 있으므로 다시 등록하기 전에 이전 등록을 해제하세요. 반환값의 dispose()를 호출하면 등록된 기본 컴포넌트로 돌아갑니다. { override: false }는 기본 컴포넌트를 등록합니다.

해당 뷰를 처음 열기 전에 등록하세요. 등록을 바꿔도 이미 마운트된 뷰가 자동으로 다시 렌더링되지는 않습니다.

Sheets 패키지의 공개 진입점에서 다음 키를 가져와 해당 기본 컴포넌트를 재정의할 수 있습니다.

컴포넌트공개 키패키지
정의된 이름DEFINED_NAME_CONTAINER@univerjs/sheets-ui
추가 함수MORE_FUNCTIONS_COMPONENT@univerjs/sheets-formula-ui
데이터 유효성 검사DATA_VALIDATION_PANEL@univerjs/sheets-data-validation-ui
조건부 서식CF_PANEL_KEY@univerjs/sheets-conditional-formatting-ui

예를 들어 기본 제공 ColorPicker 컴포넌트는 다음과 같이 간단히 교체할 수 있습니다.

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

콘텐츠 컴포넌트로 사용

사이드바에서 사용

univerAPI.openSidebar 메서드를 사용하면 Univer 인터페이스에서 사용자 지정 컴포넌트가 포함된 사이드바를 열 수 있습니다.

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()

참조: univerAPI.openSidebar

대화 상자에서 사용

univerAPI.openDialog 메서드를 사용하면 사용자 지정 컴포넌트가 포함된 대화 상자를 열 수 있습니다.

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()

참조: univerAPI.openDialog

셀에 팝업 연결

FRange.attachPopup 메서드를 사용하면 특정 셀 범위에 사용자 지정 팝업을 연결할 수 있습니다.

  • 팝업은 셀에 연결되는 임시 DOM 요소입니다. 일반적으로 일시적인 상태 정보를 표시하는 데 사용하며 영구 저장은 지원하지 않습니다.
  • FRange.attachPopup(popup: IFCanvasPopup) 메서드를 사용하면 특정 셀 범위에 사용자 지정 팝업을 연결할 수 있습니다.
  • 팝업은 셀 가장자리에 붙으며, 가려질 경우 위치와 방향을 자동으로 조정합니다.
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()

경고 팝업 연결

FRange.attachAlertPopup 메서드를 사용하면 지정한 범위의 시작 셀에 경고 팝업을 연결할 수 있습니다.

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()

워크시트에 플로팅 DOM 추가

FWorksheet.addFloatDomToPosition 메서드를 사용하면 워크시트에 플로팅 DOM을 추가할 수 있습니다.

  • 이 메서드를 사용하기 전에 @univerjs/sheets-drawing-ui 플러그인 또는 @univerjs/preset-sheets-drawing 프리셋을 설치해야 합니다.
  • 플로팅 DOM은 워크시트 위에 떠 있는 드래그 가능한 컴포넌트이며 영구 저장을 지원합니다.
  • Univer의 렌더링이 끝난 뒤 이 메서드를 호출해야 합니다.
  • componentKey: Univer 내부에서 컴포넌트를 참조하는 데 사용하는 고유 식별자입니다.
  • 전체 매개변수 정의
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()

이 가이드는 어떠셨나요?

© 2026 DreamNum Co., Ltd.