Skip to main content
Version: 1.1

Migrating to v1.1

1.1 is a minor release: nothing public was removed, and code written for 1.0 keeps compiling and running. No code changes are required. It rebuilds the editor core, fixes a long list of bugs, adds a few options and methods, and brings back custom keyboards. This page lists the upgrade steps, the optional improvements, and what behaves differently.

Upgrade steps​

  1. Update the package (and react-native-webview, if it is older than 13.7):

    yarn add @10play/tentap-editor@^1.1.0
  2. Rebuild your native app. 1.1 contains a small autolinked native module (TenTapKeyboard), used by custom keyboards. Until you rebuild, the editor works and custom keyboards use the JavaScript fallback driver.

    • iOS: cd ios && pod install
    • Android: a new Gradle build
    • Expo: npx expo prebuild, or rebuild your dev client. Expo Go keeps working without a rebuild.
  3. If you use the advanced setup, rebuild your editor bundle and follow Upgrading your editor-web.

    • Coming from 0.x, delete the old editorHtml.ts from your build folder (for example editor-web/build/editorHtml.ts). Since 1.0, buildEditor.js writes editorHtml.js and editorHtml.d.ts instead, and a Vite config with emptyOutDir: false keeps the old file. Metro resolves .ts before .js, so import { editorHtml } from './editor-web/build/editorHtml' would keep loading the 0.x bundle. editor:build prints a warning while such a file exists.
  4. Coming from 0.7.x, also follow the 1.0 migration guide. In particular, TipTap v3 renamed History to UndoRedo, so HistoryBridge is named undoRedo; code that looks bridges up by 'history' must use 'undoRedo'. 1.1 also sends the bridge's config under history, so a custom editor bundle built with 0.7.x still receives it.

Requirements​

  • React Native 0.74 or newer (Expo SDK 51 or newer) for the native module. The Android module is built on BaseReactPackage, which was added in 0.74, so the Android build fails on older versions. The react-native peer dependency is still *, so package managers don't check this. Stay on 1.0.x if you can't upgrade React Native.
  • react-native-webview 13.7 or newer. Use 13.13.3 or newer on the new architecture if the editor is inside a ScrollView.
  • The Android package is still com.tentap.TenTapViewPackage, now written in Java. The library no longer applies the Kotlin Gradle plugin, which conflicted with AGP 9's built-in Kotlin support.
  • package.json declares a codegenConfig again (RNTenTapSpec, a native module). If a build fails on stale codegen output after upgrading, clean the build folders (ios/build, android/app/build) and rebuild.
  • @tiptap/react is still a dependency, so a 1.0 advanced setup that imports EditorContent from @tiptap/react keeps building. Importing it from @10play/tentap-editor instead is recommended (Sharing tiptap).
  • react-dom is no longer installed with the package. 1.0.1 depended on react-dom@^18.2.0, and a React 19 app then got a second, nested react-dom 18, which expo-doctor reports as a duplicate (#315). The built-in editor is prebuilt with its own copy, and the native bundle never loads react-dom. Web apps and custom editor bundles keep a react-dom that matches their react, as in advanced setup. A native-only app needs nothing extra. @tiptap/react still lists react-dom as a peer dependency, so a native-only install may print a peer warning; that warning is safe to ignore.

Optional: the new keyboard layout​

The 1.0 layout, a KeyboardAvoidingView around the Toolbar with a keyboardVerticalOffset below a header, keeps working. 1.1 adds EditorKeyboardAvoidingView, which needs no offset and also keeps the toolbar on the keyboard on edge-to-edge Android (the default in Expo SDK 53+). Swapping it in is a one-line change; see Keyboard and caret.

Custom keyboards are back​

CustomKeyboard, ColorKeyboard, CustomKeyboardExtension, the colorKeyboard theme and the Color / ColorKeyboardTheme types are exported again. See Custom Keyboard Utils.

Coming from 0.7.x:

  • Your code compiles unchanged. rootRef is ignored and can be removed.
  • The keyboard component is now rendered in your app's own React tree. It can use your context providers and hooks, including useBridgeState(editor) to follow the editor state. It also receives editor, close and keyboardHeight props.
  • It works on the new architecture, including bridgeless mode and the React Native 0.79+ app templates.
  • TenTapView is a deprecated component that renders nothing. Remove it.
  • colorKeyboard is optional on EditorTheme, so a full theme object written for 1.0 still type-checks. editor.theme, defaultEditorTheme and darkEditorTheme are typed with it, so editor.theme.colorKeyboard.keyboardRootColor compiles as in 0.7.x.
  • The toolbar stays visible while a custom keyboard is open, so you can drop the hidden logic from the 0.7.x examples.

New options and methods​

parseOptionsProseMirror parse options, e.g. to keep whitespace
scrollBottomOffsetextra space kept below the cursor
avoidKeyboardalias of avoidIosKeyboard
mergeStylesmerge the RichText style prop instead of replacing
rpcTimeoutMstimeout for getHTML and the other async methods
insertContentinsert HTML, text or JSON at the cursor
getSelectedTextread the selected text
setContent(content, options)parseOptions and emitUpdate per call
Toolbar headingItemscustomize the heading toolbar; HEADING_ITEMS and ToolbarContext are exported
TentapRpcTimeoutError, TentapUnsupportedErrorerrors thrown by the async methods
useRemoteEditorBridgesubscribes to the most recently created editor
Toolbar ListComponentrender the toolbar with another list component, such as a bottom-sheet FlatList
linkBarTheme.hintTextplaceholder of the link bar input
useTenTap stateUpdateDebounceMsdebounce of state updates from a custom editor bundle

Behaviour changes​

These are fixes, but they change what some apps observe.

Editor identity

  • useEditorBridge returns the same object on every render, so it is safe in dependency arrays; its option fields (theme, dynamicHeight, …) always read the latest render. RichText and Toolbar re-render when the options change, also under a React.memo parent. Your own memoized components that render from editor.theme or another option should take that value as a prop, since editor alone no longer changes.

Readiness and messaging

  • isReady becomes true as soon as the editor is created, also when it is not editable and not focused. It goes back to false while the WebView reloads.
  • Commands called before the editor is ready are queued and sent in order once it is ready. They used to be dropped with an "Editor isn't ready yet" warning.
  • The web editor sends editor-ready followed by a full stateUpdate as soon as it is created.
  • If you read messages in your own onMessage: messages can carry extra fields (editorId, v) besides type and payload, editor-ready has a payload, and there are new message types (boot-error, tentap-editor-press). Ignore what you don't use. A development warning is logged when onMessage is passed without exclusivelyUseCustomOnMessage; the default is still true.
  • If the WebView's content process is killed, the editor reloads and restores its content and settings. Edits made since the content was last read can be lost.
  • On iOS, the WebView is remounted after its first load only with react-native-webview 13.12.3 and 13.12.4, which need the workaround.
  • useEditorContent fetches the content when it changes, not on every selection change.
  • Bridge configs containing quotes or </script> no longer break the editor.

Layout

  • style and containerStyle passed to RichText still replace the editor's own styles, as in 1.0, unless you set the new mergeStyles option. The difference: with dynamicHeight, the content height is now applied after your containerStyle, so your styles can no longer switch dynamic height off by accident.
  • RichText throws a clear error when editor doesn't come from useEditorBridge. A spread copy such as { ...editor } still works, as in 1.0, but its option fields are a snapshot, so prefer passing editor itself.
  • dynamicHeight works in any parent, shrinks when content is deleted, keeps the scroll position when the height is capped, and no longer adds keyboard padding.

Keyboard and caret

  • RichText measures how far the keyboard and the toolbar on it reach into the editor, and keeps the line being typed about one line above the toolbar. In 1.0 the inset was derived from the keyboard height (iOS) or a fixed toolbar height (Android), so the caret could end up under the toolbar. The document padding and the scroll threshold now come from this measurement.
  • This applies to every editor without dynamicHeight while a keyboard is up, also without avoidIosKeyboard. An editor that ends above the keyboard keeps about one line of space below the caret. Until the first measurement, avoidIosKeyboard keeps its 1.0 value.
  • A toolbar of your own on the keyboard that isn't marked with useKeyboardAccessory gets the default toolbar height of room.
  • useKeyboard() keeps keyboardHeight while switching between the system and a custom keyboard, and returns new fields. isKeyboardUp and keyboardHeight behave as in 1.0 when no custom keyboard is used.

Editing

  • setImage adds an empty paragraph after an image that ends the document and moves the cursor there.
  • Links without a scheme get https:// (www.google.com → https://www.google.com), or the defaultProtocol passed to LinkBridge.configureExtension. Plain email addresses get mailto:.
  • CSS injected with injectCSS is re-applied when the WebView reloads.

Toolbar

  • shouldHideDisabledToolbarItems also hides disabled heading items.
  • The link bar no longer closes when its input loses focus. The keyboard's Done key inserts the link.
  • Each toolbar context renders its own list, so the heading toolbar opens scrolled to the start.

Advanced setup

  • tiptapOptions.onCreate, onUpdate, onSelectionUpdate and onTransaction passed to useTenTap run in addition to tentap's handlers instead of replacing them. If you overrode them on purpose to stop tentap's messages, that no longer works.
  • Bridges and extensions are resolved once, when the editor is created.

Type-level changes​

  • EditorBridge (with CoreBridge) has two new required members, insertContent and getSelectedText. If you build EditorBridge objects by hand, for example as test mocks, add them.
  • setContent has a new optional second parameter.
  • EditorTheme has a new optional colorKeyboard key.
  • The source types are self-contained: deep imports from @10play/tentap-editor/src/... and moduleResolution: "node" no longer report missing bridge methods such as toggleBold. Importing from the package root is still recommended.
  • extendEditorInstance receives an optional sixth argument, BridgeContext. Existing five-argument bridges are unaffected.

Deprecations​

DeprecatedUse instead
CustomKeyboard rootRef propnothing, it's ignored
TenTapViewnothing, it renders nothing
CustomKeyboard onKeyboardHideAndroid proponClose

Deprecated APIs keep working in 1.x. avoidIosKeyboard is not deprecated; avoidKeyboard is an alias with a clearer name.