Skip to main content
ProseKit provides first-class support for Solid through the @prosekit/solid package, offering Solid-specific components, primitives, and utilities for building powerful editors.

Installation

npm install prosekit @prosekit/solid
Peer dependencies:
  • solid-js >= 1.7.0

Quick Start

Create a basic editor with Solid:
import { createEditor } from '@prosekit/core'
import { ProseKit, useEditor } from '@prosekit/solid'
import { defineBasicExtension } from '@prosekit/extensions'
import { onMount } from 'solid-js'

function Editor() {
  const editor = createEditor({
    extension: defineBasicExtension()
  })

  return (
    <ProseKit editor={editor}>
      <EditorContent />
    </ProseKit>
  )
}

function EditorContent() {
  const editor = useEditor()
  let editorRef: HTMLDivElement | undefined

  onMount(() => {
    if (editorRef) {
      editor().mount(editorRef)
    }
  })

  return <div ref={editorRef} />
}

Core Components

ProseKit

The root component that provides editor context to all child components.
import { ProseKit } from '@prosekit/solid'
import type { ProseKitProps } from '@prosekit/solid'

<ProseKit editor={editor}>
  {/* Your editor UI components */}
</ProseKit>
Props:
  • editor: The editor instance created with createEditor()
  • children?: Child components

Essential Primitives

useEditor

Retrieves the editor instance from the nearest ProseKit component.
import { useEditor } from '@prosekit/solid'

function Toolbar() {
  const editor = useEditor()
  
  const toggleBold = () => {
    editor().commands.toggleBold()
  }
  
  return <button onClick={toggleBold}>Bold</button>
}
Returns: () => Editor (Solid accessor) Options:
  • update?: boolean - Whether to trigger reactivity when editor state updates (default: false)
// Trigger reactivity on every state update
const editor = useEditor({ update: true })

useEditorDerivedValue

Compute and subscribe to derived values from the editor state.
import { useEditorDerivedValue } from '@prosekit/solid'

function StatusBar() {
  const wordCount = useEditorDerivedValue((editor) => {
    return editor.state.doc.textContent.split(/\s+/).length
  })
  
  return <div>Words: {wordCount()}</div>
}

useExtension

Dynamically add extensions to the editor.
import { useExtension } from '@prosekit/solid'
import { defineCodeBlock } from '@prosekit/extensions'
import { createMemo } from 'solid-js'

function CodeBlockPlugin(props: { enabled: boolean }) {
  const extension = createMemo(() => 
    props.enabled ? defineCodeBlock() : null
  )
  
  useExtension(extension)
  
  return null
}
Options:
  • editor?: Editor - Optional editor instance (defaults to context editor)
  • priority?: Priority - Extension priority

useKeymap

Define keyboard shortcuts.
import { useKeymap } from '@prosekit/solid'

function SavePlugin() {
  useKeymap({
    'Mod-s': () => {
      console.log('Save triggered')
      return true
    }
  })
  
  return null
}

useDocChange

Execute a callback when the document changes.
import { useDocChange } from '@prosekit/solid'

function AutoSave() {
  useDocChange((editor) => {
    const json = editor.getDocJSON()
    localStorage.setItem('doc', JSON.stringify(json))
  })
  
  return null
}

useStateUpdate

Execute a callback on every state update (including selection changes).
import { useStateUpdate } from '@prosekit/solid'
import { createSignal } from 'solid-js'

function SelectionTracker() {
  const [selection, setSelection] = createSignal({ from: 0, to: 0 })
  
  useStateUpdate((editor) => {
    const { from, to } = editor.state.selection
    setSelection({ from, to })
  })
  
  return <div>Selection: {selection().from} - {selection().to}</div>
}

Custom Node Views

Create interactive node views with Solid components:
import { defineSolidNodeView } from '@prosekit/solid'
import type { SolidNodeViewProps } from '@prosekit/solid'

function ImageComponent(props: SolidNodeViewProps) {
  const handleClick = () => {
    props.setAttrs({ selected: true })
  }
  
  return (
    <img 
      src={props.node.attrs.src} 
      alt={props.node.attrs.alt}
      onClick={handleClick}
    />
  )
}

const imageExtension = defineSolidNodeView({
  name: 'image',
  component: ImageComponent,
  contentDOM: false,
})
SolidNodeViewProps:
  • node - The ProseMirror node
  • view - The editor view
  • getPos - Function to get node position
  • setAttrs - Function to update node attributes
  • decorations - Node decorations
  • selected - Whether the node is selected

Custom Mark Views

Create custom mark rendering with Solid:
import { defineSolidMarkView } from '@prosekit/solid'
import type { SolidMarkViewProps } from '@prosekit/solid'

function CommentMark(props: SolidMarkViewProps) {
  const commentId = () => props.mark.attrs.id
  
  return (
    <span 
      class="comment"
      data-comment-id={commentId()}
    >
      {props.children}
    </span>
  )
}

const commentExtension = defineSolidMarkView({
  name: 'comment',
  component: CommentMark,
})

UI Components

ProseKit provides pre-built Solid components for common editor UI patterns:

Autocomplete

import { 
  AutocompletePopover, 
  AutocompleteItem, 
  AutocompleteList, 
  AutocompleteEmpty 
} from '@prosekit/solid/autocomplete'

<AutocompletePopover>
  <AutocompleteList>
    <AutocompleteEmpty>No results</AutocompleteEmpty>
    <AutocompleteItem value="solid">Solid</AutocompleteItem>
    <AutocompleteItem value="react">React</AutocompleteItem>
  </AutocompleteList>
</AutocompletePopover>

Inline Popover

import { InlinePopover } from '@prosekit/solid/inline-popover'

<InlinePopover>
  <button>Bold</button>
  <button>Italic</button>
</InlinePopover>

Tooltip

import { TooltipRoot, TooltipTrigger, TooltipContent } from '@prosekit/solid/tooltip'

<TooltipRoot>
  <TooltipTrigger>
    <button>Hover me</button>
  </TooltipTrigger>
  <TooltipContent>
    Tooltip text
  </TooltipContent>
</TooltipRoot>

Popover

import { PopoverRoot, PopoverTrigger, PopoverContent } from '@prosekit/solid/popover'

<PopoverRoot>
  <PopoverTrigger>
    <button>Open</button>
  </PopoverTrigger>
  <PopoverContent>
    Popover content
  </PopoverContent>
</PopoverRoot>

Block Handle

import { BlockHandleDraggable, BlockHandleAdd, BlockHandlePopover } from '@prosekit/solid/block-handle'

<BlockHandleDraggable />
<BlockHandleAdd />
<BlockHandlePopover>
  {/* Block options */}
</BlockHandlePopover>

Table Handle

import { 
  TableHandleRoot,
  TableHandleColumnRoot,
  TableHandleColumnTrigger,
  TableHandleRowRoot,
  TableHandleRowTrigger 
} from '@prosekit/solid/table-handle'

<TableHandleRoot>
  <TableHandleColumnRoot>
    <TableHandleColumnTrigger />
  </TableHandleColumnRoot>
  <TableHandleRowRoot>
    <TableHandleRowTrigger />
  </TableHandleRowRoot>
</TableHandleRoot>

Resizable

import { ResizableRoot, ResizableHandle } from '@prosekit/solid/resizable'

<ResizableRoot>
  <img src="image.jpg" />
  <ResizableHandle />
</ResizableRoot>

TypeScript Support

ProseKit has full TypeScript support with type inference:
import { createEditor } from '@prosekit/core'
import { useEditor } from '@prosekit/solid'
import { defineBasicExtension } from '@prosekit/extensions'

const extension = defineBasicExtension()

const editor = createEditor({ extension })
// Editor type is automatically inferred

function MyComponent() {
  const editor = useEditor()
  // editor().commands has autocomplete for all available commands
  editor().commands.toggleBold()
}

Reactive Primitives

ProseKit integrates seamlessly with Solid’s reactive primitives:
import { createEditor } from '@prosekit/core'
import { ProseKit, useEditor } from '@prosekit/solid'
import { defineBasicExtension } from '@prosekit/extensions'
import { createSignal, createEffect } from 'solid-js'

function Editor() {
  const [content, setContent] = createSignal('')
  
  const editor = createEditor({
    extension: defineBasicExtension()
  })
  
  const editorRef = useEditor()
  
  createEffect(() => {
    setContent(editorRef().state.doc.textContent)
  })
  
  return (
    <ProseKit editor={editor}>
      <div>Content length: {content().length}</div>
    </ProseKit>
  )
}

Server-Side Rendering (SSR)

ProseKit supports server-side rendering with SolidStart:
import { createEditor } from '@prosekit/core'
import { ProseKit } from '@prosekit/solid'
import { defineBasicExtension } from '@prosekit/extensions'
import { createSignal, onMount, Show } from 'solid-js'
import { isServer } from 'solid-js/web'

function Editor() {
  const [editor, setEditor] = createSignal(null)
  
  onMount(() => {
    if (!isServer) {
      setEditor(createEditor({ 
        extension: defineBasicExtension() 
      }))
    }
  })
  
  return (
    <Show when={editor()}>
      {(ed) => (
        <ProseKit editor={ed()}>
          {/* Editor components */}
        </ProseKit>
      )}
    </Show>
  )
}

Examples

Check out full working examples:

Next Steps

Extensions

Learn about available extensions

Commands

Explore editor commands

Styling

Customize editor appearance

API Reference

Full API documentation