Skip to main content

Overview

ProseKit provides a collection of helper utilities that make common editor operations easier and more convenient.

Node Utilities

findNode()

Finds the first node that satisfies a predicate in the document.
function findNode(
  doc: ProseMirrorNode,
  predicate: (node: ProseMirrorNode) => boolean
): FindNodeResult | undefined

Parameters

doc
ProseMirrorNode
required
The document to search in
predicate
(node: ProseMirrorNode) => boolean
required
A function that returns true for the node you’re looking for

Return Value

result
FindNodeResult | undefined
An object containing the found node and its position, or undefined if not found.
result.node
ProseMirrorNode
The node that satisfies the predicate
result.pos
number
The position of the node in the document
result.parent
ProseMirrorNode | null
The parent of the node
result.index
number
The index of the node in its parent

Example

import { findNode } from 'prosekit/core'

const result = findNode(
  editor.state.doc,
  node => node.type.name === 'heading' && node.attrs.level === 1
)

if (result) {
  console.log('Found H1 at position:', result.pos)
  console.log('Content:', result.node.textContent)
}

findNodes()

Finds all nodes that satisfy a predicate in the document.
function findNodes(
  doc: ProseMirrorNode,
  predicate: (node: ProseMirrorNode) => boolean
): FindNodeResult[]

Parameters

doc
ProseMirrorNode
required
The document to search in
predicate
(node: ProseMirrorNode) => boolean
required
A function that returns true for nodes you’re looking for

Return Value

results
FindNodeResult[]
An array of objects containing the found nodes and their positions

Example

import { findNodes } from 'prosekit/core'

// Find all images
const images = findNodes(
  editor.state.doc,
  node => node.type.name === 'image'
)

console.log(`Found ${images.length} images`)
images.forEach(img => {
  console.log('Image at:', img.pos, 'src:', img.node.attrs.src)
})

findParentNode()

Finds the nearest parent node that satisfies a predicate.
function findParentNode(
  predicate: (node: ProseMirrorNode) => boolean
): FindParentNodeResult | undefined

Example

import { findParentNode } from 'prosekit/core'

const { selection } = editor.state
const $pos = selection.$from

const listParent = findParentNode(
  node => node.type.name === 'bulletList' || node.type.name === 'orderedList'
)($pos)

if (listParent) {
  console.log('Inside a list at depth:', listParent.depth)
}

findParentNodeOfType()

Finds the nearest parent node of a specific type.
function findParentNodeOfType(
  type: string | NodeType
): FindParentNodeResult | undefined

Example

import { findParentNodeOfType } from 'prosekit/core'

const { selection } = editor.state
const tableParent = findParentNodeOfType('table')(selection.$from)

if (tableParent) {
  console.log('Inside a table')
}

Type Utilities

getMarkType()

Gets a MarkType from the schema by name or returns the MarkType if already provided.
function getMarkType(schema: Schema, type: string | MarkType): MarkType

Parameters

schema
Schema
required
The editor schema
type
string | MarkType
required
The mark type name or MarkType instance

Return Value

markType
MarkType
The MarkType instance. Throws an error if the type doesn’t exist in the schema.

Example

import { getMarkType } from 'prosekit/core'

const boldType = getMarkType(editor.schema, 'bold')
const boldMark = boldType.create()

getNodeType()

Gets a NodeType from the schema by name or returns the NodeType if already provided.
function getNodeType(schema: Schema, type: string | NodeType): NodeType

Parameters

schema
Schema
required
The editor schema
type
string | NodeType
required
The node type name or NodeType instance

Return Value

nodeType
NodeType
The NodeType instance. Throws an error if the type doesn’t exist in the schema.

Example

import { getNodeType } from 'prosekit/core'

const paragraphType = getNodeType(editor.schema, 'paragraph')
const paragraph = paragraphType.create()

State Checking Utilities

isMarkActive()

Checks if a mark is active in the current selection.
function isMarkActive(
  state: EditorState,
  type: string | MarkType,
  attrs?: Attrs | null
): boolean

Parameters

state
EditorState
required
The editor state
type
string | MarkType
required
The mark type to check
attrs
Attrs | null
Optional attributes to match

Return Value

active
boolean
Returns true if the mark is active in the selection, false otherwise

Example

import { isMarkActive } from 'prosekit/core'

const isBold = isMarkActive(editor.state, 'bold')

if (isBold) {
  console.log('Bold is active')
}

// Check with specific attributes
const hasYellowHighlight = isMarkActive(
  editor.state,
  'highlight',
  { color: 'yellow' }
)

isMarkAbsent()

Checks if a mark is completely absent from a range.
function isMarkAbsent(
  doc: ProseMirrorNode,
  from: number,
  to: number,
  type: MarkType,
  attrs?: Attrs | null
): boolean

Example

import { isMarkAbsent, getMarkType } from 'prosekit/core'

const boldType = getMarkType(editor.schema, 'bold')
const noBold = isMarkAbsent(
  editor.state.doc,
  10,
  20,
  boldType
)

isAtBlockStart()

Checks if the selection is at the start of a block.
function isAtBlockStart(state: EditorState): boolean

Example

import { isAtBlockStart } from 'prosekit/core'

if (isAtBlockStart(editor.state)) {
  console.log('Cursor is at the start of a block')
}

isInCodeBlock()

Checks if the selection is inside a code block.
function isInCodeBlock(state: EditorState): boolean

Example

import { isInCodeBlock } from 'prosekit/core'

if (isInCodeBlock(editor.state)) {
  console.log('Inside a code block')
}

Content Utilities

containsInlineNode()

Checks if a node contains inline content.
function containsInlineNode(node: ProseMirrorNode): boolean

Example

import { containsInlineNode } from 'prosekit/core'

const node = editor.state.doc.firstChild

if (containsInlineNode(node)) {
  console.log('Node contains inline content')
}

defaultBlockAt()

Finds the default block type at a given position.
function defaultBlockAt(pos: ResolvedPos): NodeType | null

Example

import { defaultBlockAt } from 'prosekit/core'

const { $from } = editor.state.selection
const defaultBlock = defaultBlockAt($from)

if (defaultBlock) {
  console.log('Default block type:', defaultBlock.name)
}

Environment Utilities

isApple()

Checks if the current platform is macOS or iOS.
function isApple(): boolean

Example

import { isApple } from 'prosekit/core'

const modKey = isApple() ? 'Cmd' : 'Ctrl'
console.log(`Use ${modKey}+B for bold`)

canUseRegexLookbehind()

Checks if the environment supports regex lookbehind.
function canUseRegexLookbehind(): boolean

Example

import { canUseRegexLookbehind } from 'prosekit/core'

if (canUseRegexLookbehind()) {
  // Use advanced regex features
}

Utility Functions

assert()

Throws an error if a condition is not met.
function assert(condition: unknown, message?: string): asserts condition

Example

import { assert } from 'prosekit/core'

function processNode(node: ProseMirrorNode | null) {
  assert(node, 'Node must be defined')
  // TypeScript knows node is not null here
  console.log(node.type.name)
}

clsx()

Utility for conditionally constructing className strings.
function clsx(...args: ClassValue[]): string

Example

import { clsx } from 'prosekit/core'

const className = clsx(
  'editor',
  isActive && 'active',
  { 'dark-mode': isDark },
  ['foo', 'bar']
)
// Result: 'editor active dark-mode foo bar'

maybeRun()

Runs a function if it exists and returns its result.
function maybeRun<T>(
  fn: (() => T) | undefined | null
): T | undefined

Example

import { maybeRun } from 'prosekit/core'

const result = maybeRun(config.onInit)
if (result) {
  console.log('Init result:', result)
}

withSkipCodeBlock()

Wraps a command to skip execution when inside a code block.
function withSkipCodeBlock(command: Command): Command

Example

import { withSkipCodeBlock } from 'prosekit/core'
import { toggleMark } from 'prosekit/core'

// Bold won't work inside code blocks
const safeBold = withSkipCodeBlock(
  toggleMark({ type: 'bold' })
)

Common Patterns

Finding Specific Content

import { findNodes } from 'prosekit/core'

function findAllLinks(editor) {
  return findNodes(
    editor.state.doc,
    node => node.marks.some(mark => mark.type.name === 'link')
  )
}

function findEmptyParagraphs(editor) {
  return findNodes(
    editor.state.doc,
    node => node.type.name === 'paragraph' && node.childCount === 0
  )
}

Checking Editor State

import { isMarkActive, isAtBlockStart, isInCodeBlock } from 'prosekit/core'

function getEditorStatus(editor) {
  return {
    bold: isMarkActive(editor.state, 'bold'),
    italic: isMarkActive(editor.state, 'italic'),
    atStart: isAtBlockStart(editor.state),
    inCode: isInCodeBlock(editor.state)
  }
}

Platform-Specific Behavior

import { isApple } from 'prosekit/core'
import { defineKeymap } from 'prosekit/core'

function createPlatformKeymap() {
  const modKey = isApple() ? 'Cmd' : 'Ctrl'
  
  return defineKeymap({
    [`${modKey}-b`]: toggleMark({ type: 'bold' }),
    [`${modKey}-i`]: toggleMark({ type: 'italic' })
  })
}

Safe Command Execution

import { withSkipCodeBlock } from 'prosekit/core'
import { toggleMark } from 'prosekit/core'

const safeCommands = {
  bold: withSkipCodeBlock(toggleMark({ type: 'bold' })),
  italic: withSkipCodeBlock(toggleMark({ type: 'italic' })),
  // Code blocks should still work
  code: toggleMark({ type: 'code' })
}

See Also