React

GitHubEdit on GitHub

If you are looking for how to use React components as custom components, please refer to here.

React 17、18、19

Integration Steps

  1. Initialize Univer in the useEffect hook
  2. Destroy Univer in the return function of the useEffect hook

Example

import { UniverSheetsCorePreset } from '@univerjs/preset-sheets-core'
import UniverPresetSheetsCoreEnUS from '@univerjs/preset-sheets-core/locales/en-US'
import { createUniver, LocaleType, merge } from '@univerjs/presets'
import React, { useEffect, useRef } from 'react'

import '@univerjs/preset-sheets-core/lib/index.css'

export function App() {
  const containerRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const { univerAPI } = createUniver({
      locale: LocaleType.EN_US,
      locales: {
        [LocaleType.EN_US]: merge(
          {},
          UniverPresetSheetsCoreEnUS,
        ),
      },
      presets: [
        UniverSheetsCorePreset({
          container: containerRef.current,
        }),
      ],
    })

    univerAPI.createWorkbook({})

    return () => {
      univerAPI.dispose()
    }
  }, [])

  return (
    <div ref={containerRef} />
  )
}

React 16.9+

Notes before integration

  • Although Univer's view layer is developed based on React 18.3.1, we provide minimal compatibility for projects using React 16.9+. However, this does not mean that Univer will indefinitely support lower versions of React. All software needs to be updated continuously to adapt to new technologies and requirements, so we still recommend upgrading to the latest version of React as soon as possible.
  • To use Univer in React 16.9+, you need to use the alias feature of your build tool to simulate the export of react-dom/client:
vite.config.ts
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      'react-dom/client': path.resolve(__dirname, './src/client.ts'), 
    },
  },
})
src/client.ts
import ReactDOM from 'react-dom'

export function createRoot(container: HTMLElement) {
  return {
    render: (element: JSX.Element) => {
      ReactDOM.render(element, container)
    },
  }
}
  • If you are not using a build tool and are including Univer and React via <script> tags, you also need to ensure that the following code is added after importing React to simulate the export of react-dom/client:
<script>
  /**
   * With the support for React 19[^1], UMD users may need additional adaptation.
   *
   * [^1]: [support for React 19] https://github.com/dream-num/univer/pull/4247
   */

  /**
   * Fix `Uncaught TypeError: client.createRoot is not a function`
   * If using UMD React < 18, you might need the following code.
   */
  ;(function (global) {
    'use strict'
    if (!global.ReactDOM) {
      throw new Error('ReactDOM must be loaded before ReactCreateRoot.')
    }
    const ReactDOM = global.ReactDOM
    if (!ReactDOM.createRoot) {
      ReactDOM.createRoot = function (container) {
        return {
          render: (element) => {
            ReactDOM.render(element, container)
          },
        }
      }
    }
  })(this)

  /**
   * Fix `Uncaught TypeError: jsxRuntime.jsx is not a function`
   * If using UMD React, you might need the following code.
   * Reference: https://unpkg.com/react@18.3.1/cjs/react-jsx-runtime.production.min.js
   */
  ;(function (global) {
    'use strict'
    if (!global.React) {
      throw new Error('React must be loaded before ReactJSXRuntime.')
    }
    const React = global.React
    if (!React.jsx || !React.jsxs) {
      const REACT_ELEMENT_TYPE = Symbol.for('react.element')
      const hasOwnProperty = Object.prototype.hasOwnProperty
      const RESERVED_PROPS = {
        key: true,
        ref: true,
        __self: true,
        __source: true,
      }
      const ReactCurrentOwner = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner
      function createReactElement(type, config, maybeKey) {
        const props = {}
        let key = null
        let ref = null
        if (maybeKey !== undefined) {
          key = `${maybeKey}`
        }
        if (config.key !== undefined) {
          key = `${config.key}`
        }
        if (config.ref !== undefined) {
          ref = config.ref
        }
        for (var propName in config) {
          if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
            props[propName] = config[propName]
          }
        }
        if (type && type.defaultProps) {
          const defaultProps = type.defaultProps
          for (var propName in defaultProps) {
            if (props[propName] === undefined) {
              props[propName] = defaultProps[propName]
            }
          }
        }
        return {
          $$typeof: REACT_ELEMENT_TYPE,
          type,
          key,
          ref,
          props,
          _owner: ReactCurrentOwner.current,
        }
      }
      React.jsx = createReactElement
      React.jsxs = createReactElement
    }
  })(this)
</script>

Integration Steps

  1. Initialize Univer in the useEffect hook
  2. Destroy Univer in the return function of the useEffect hook

Example

import { UniverSheetsCorePreset } from '@univerjs/preset-sheets-core'

import UniverPresetSheetsCoreEnUS from '@univerjs/preset-sheets-core/locales/en-US'
import { createUniver, LocaleType, merge } from '@univerjs/presets'
import React, { useEffect, useRef } from 'react'

import '@univerjs/preset-sheets-core/lib/index.css'

export function App() {
  const containerRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const { univerAPI } = createUniver({
      locale: LocaleType.EN_US,
      locales: {
        [LocaleType.EN_US]: merge(
          {},
          UniverPresetSheetsCoreEnUS,
        ),
      },
      presets: [
        UniverSheetsCorePreset({
          container: containerRef.current,
        }),
      ],
    })

    univerAPI.createWorkbook({})

    return () => {
      univerAPI.dispose()
    }
  }, [])

  return (
    <div ref={containerRef} />
  )
}