Skip to content

React

ProseKit has first-class support for React via prosekit/react.

<ProseKit editor={editor}> provides context to its descendants. The component itself does not render any DOM, it only forwards children.

'use client'

import 'prosekit/basic/style.css'
import 'prosekit/basic/typography.css'

import { defineBasicExtensionfunction defineBasicExtension(): BasicExtension
Define a basic extension that includes some common functionality. You can copy this function and customize it to your needs. It's a combination of the following extension functions: - {@link defineDoc } - {@link defineText } - {@link defineParagraph } - {@link defineHeading } - {@link defineList } - {@link defineBlockquote } - {@link defineImage } - {@link defineHorizontalRule } - {@link defineHardBreak } - {@link defineTable } - {@link defineCodeBlock } - {@link defineItalic } - {@link defineBold } - {@link defineUnderline } - {@link defineStrike } - {@link defineCode } - {@link defineLink } - {@link defineBaseKeymap } - {@link defineBaseCommands } - {@link defineHistory } - {@link defineGapCursor } - {@link defineVirtualSelection } - {@link defineModClickPrevention }
@public
} from 'prosekit/basic'
import { createEditorfunction createEditor<E extends Extension>(options: EditorOptions<E>): Editor<E>
@public
} from 'prosekit/core'
import { ProseKitconst ProseKit: ComponentType<ProseKitProps>
The root component for a ProseKit editor.
@public
} from 'prosekit/react'
import { useMemofunction useMemo<T>(factory: () => T, deps: DependencyList): T
`useMemo` will only recompute the memoized value when one of the `deps` has changed.
@version16.8.0@see{@link https://react.dev/reference/react/useMemo}
} from 'react'
export default function Editorfunction Editor(): JSX.Element() { const editorconst editor: Editor<BasicExtension> = useMemouseMemo<Editor<BasicExtension>>(factory: () => Editor<BasicExtension>, deps: DependencyList): Editor<BasicExtension>
`useMemo` will only recompute the memoized value when one of the `deps` has changed.
@version16.8.0@see{@link https://react.dev/reference/react/useMemo}
(() => {
return createEditorcreateEditor<BasicExtension>(options: EditorOptions<BasicExtension>): Editor<BasicExtension>
@public
({ extensionEditorOptions<BasicExtension>.extension: BasicExtension
The extension to use when creating the editor.
: defineBasicExtensionfunction defineBasicExtension(): BasicExtension
Define a basic extension that includes some common functionality. You can copy this function and customize it to your needs. It's a combination of the following extension functions: - {@link defineDoc } - {@link defineText } - {@link defineParagraph } - {@link defineHeading } - {@link defineList } - {@link defineBlockquote } - {@link defineImage } - {@link defineHorizontalRule } - {@link defineHardBreak } - {@link defineTable } - {@link defineCodeBlock } - {@link defineItalic } - {@link defineBold } - {@link defineUnderline } - {@link defineStrike } - {@link defineCode } - {@link defineLink } - {@link defineBaseKeymap } - {@link defineBaseCommands } - {@link defineHistory } - {@link defineGapCursor } - {@link defineVirtualSelection } - {@link defineModClickPrevention }
@public
() })
}, []) return ( <ProseKitconst ProseKit: ComponentType<ProseKitProps>
The root component for a ProseKit editor.
@public
editorProseKitProps.editor: Editor<any>={editorconst editor: Editor<BasicExtension>}>
<divJSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> refRefAttributes<HTMLDivElement>.ref?: Ref<HTMLDivElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
={editorconst editor: Editor<BasicExtension>.mountEditor<BasicExtension>.mount: (place: HTMLElement | null | undefined) => void | VoidFunction
Mount the editor to the given HTML element. Pass `null` or `undefined` to unmount the editor. When an element is passed, this method returns a function to unmount the editor.
} classNameHTMLAttributes<HTMLDivElement>.className?: string | undefined="editor" />
</ProseKitconst ProseKit: ComponentType<ProseKitProps>
The root component for a ProseKit editor.
@public
>
) }

All hooks are exported from prosekit/react.

useEditor(): Editor

Read the editor instance from the nearest <ProseKit> provider. The returned reference is stable; for UI that depends on editor state, use useEditorDerivedValue.

import { useEditor } from 'prosekit/react'

function BoldButton() {
  const editor = useEditor()
  return (
    <button onClick={() => editor.commands.toggleBold()}>
      Bold
    </button>
  )
}
useEditorDerivedValue(
  derive: (editor: Editor) => Derived,
  options?: { editor?: Editor },
): Derived

Compute a value from the editor and re-render whenever the editor state changes. Memoise derive (or define it outside the component), since it's used as the dependency key for the underlying store.

import type { Editor } from 'prosekit/core'
import { useEditor, useEditorDerivedValue } from 'prosekit/react'

function getToolbarState(editor: Editor) {
  return {
    boldActive: editor.marks.bold.isActive(),
    boldEnabled: editor.commands.toggleBold.canExec(),
  }
}

function Toolbar() {
  const editor = useEditor()
  const state = useEditorDerivedValue(getToolbarState)
  return (
    <button
      disabled={!state.boldEnabled}
      data-active={state.boldActive}
      onClick={() => editor.commands.toggleBold()}
    >
      Bold
    </button>
  )
}
useExtension(
  extension: Extension | null,
  options?: { editor?: Editor; priority?: Priority },
): void

Register an extension for the lifetime of the calling component. When extension changes (or becomes null), the previous one is removed and the new one is added. Useful for features that turn on/off conditionally.

import { defineCodeBlockShiki } from 'prosekit/extensions/code-block'
import { useExtension } from 'prosekit/react'

function ShikiHighlightToggle({ enabled }: { enabled: boolean }) {
  useExtension(enabled ? defineCodeBlockShiki() : null)
  return null
}
useKeymap(keymap: Keymap, options?: UseExtensionOptions): void

Bind a keymap for the lifetime of the calling component.

import { useKeymap } from 'prosekit/react'

function SaveOnCmdS({ onSave }: { onSave: () => void }) {
  useKeymap({
    'Mod-s': () => {
      onSave()
      return true
    },
  })
  return null
}
useDocChange(
  handler: (doc: ProseMirrorNode) => void,
  options?: UseExtensionOptions,
): void

Run handler whenever the editor's document changes. The handler receives the current document node. Use editor.getDocJSON() from inside if you need JSON.

import { useDocChange, useEditor } from 'prosekit/react'

function AutoSave() {
  const editor = useEditor()
  useDocChange(() => {
    localStorage.setItem('doc', JSON.stringify(editor.getDocJSON()))
  })
  return null
}
useStateUpdate(
  handler: (state: EditorState) => void,
  options?: UseExtensionOptions,
): void

Same as useDocChange but fires on every state update, including selection changes and cursor moves. Use this for selection-sensitive UI that doesn't need to wait for document edits.

defineReactNodeView(options: {
  name: string
  component: ComponentType<ReactNodeViewProps>
  // plus the standard CoreNodeViewUserOptions fields
}): Extension

Render a node with a React component. ReactNodeViewProps exposes node, view, getPos, setAttrs, decorations, and selected.

import { defineReactNodeView, type ReactNodeViewProps } from 'prosekit/react'

function ImageView(props: ReactNodeViewProps) {
  const src = String(props.node.attrs.src ?? '')
  return <img src={src} alt={String(props.node.attrs.alt ?? '')} />
}

const extension = defineReactNodeView({
  name: 'image',
  component: ImageView,
})
defineReactMarkView(options: {
  name: string
  component: ComponentType<ReactMarkViewProps>
}): Extension

Same as defineReactNodeView but for marks.