### Implement Custom MarkView for Links
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use MarkView to provide a custom DOM representation for a mark type. This example creates a 'LinkView' for the 'link' mark, setting its href, title, and target attributes.
```typescript
import { EditorView, MarkView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { Mark } from "prosemirror-model"
import { schema } from "prosemirror-schema-basic"
class LinkView implements MarkView {
dom: HTMLAnchorElement
contentDOM: HTMLAnchorElement // same element — mark content goes inside
constructor(mark: Mark, _view: EditorView, _inline: boolean) {
this.dom = document.createElement("a")
this.dom.href = mark.attrs.href
this.dom.title = mark.attrs.title || mark.attrs.href
this.dom.target = "_blank"
this.dom.rel = "noopener noreferrer"
this.contentDOM = this.dom
}
destroy() { /* any teardown */ }
}
const view = new EditorView(document.body, {
state: EditorState.create({ schema }),
markViews: {
link: (mark, view, inline) => new LinkView(mark, view, inline)
}
})
```
--------------------------------
### Handle Editor Events with EditorProps
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Customize editor behavior by returning true from event handlers like handleKeyDown, handleClick, handlePaste, and handleDrop to prevent default processing. This example demonstrates handling Tab key, Ctrl-clicks, and logging paste/drop events.
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema }),
handleKeyDown(view, event) {
if (event.key === "Tab") {
event.preventDefault()
view.dispatch(view.state.tr.insertText(" "))
return true
}
return false
},
handleClick(view, pos, event) {
if (event.ctrlKey) {
console.log("Ctrl-click at position", pos)
return true
}
return false
},
handlePaste(view, event, slice) {
console.log("Pasting", slice.content.childCount, "nodes")
return false // allow default paste
},
handleDrop(view, event, slice, moved) {
console.log(`${moved ? "Moved" : "Copied"} content:`, slice)
return false
},
handleDOMEvents: {
focus(view) {
view.dom.classList.add("is-focused")
return false
},
blur(view) {
view.dom.classList.remove("is-focused")
return false
}
}
})
```
--------------------------------
### Implement Custom NodeView for Paragraphs
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use NodeView to provide a fully custom DOM representation for a node type. This example shows a 'FancyParagraph' that adds a custom class and manages its content DOM.
```typescript
import { EditorView, NodeView, Decoration, DecorationSource } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { Node } from "prosemirror-model"
import { schema } from "prosemirror-schema-basic"
class FancyParagraph implements NodeView {
dom: HTMLElement
contentDOM: HTMLElement
constructor(
private node: Node,
private view: EditorView,
private getPos: () => number | undefined
) {
this.dom = document.createElement("div")
this.dom.className = "fancy-para"
const inner = document.createElement("p")
this.dom.appendChild(inner)
this.contentDOM = inner // ProseMirror renders children here
}
update(node: Node, _decos: readonly Decoration[], _inner: DecorationSource) {
if (node.type !== this.node.type) return false
this.node = node
this.dom.classList.toggle("has-content", node.content.size > 0)
return true
}
selectNode() { this.dom.classList.add("selected") }
deselectNode() { this.dom.classList.remove("selected") }
stopEvent(e: Event) { return e.type === "mousedown" } // absorb mousedowns
destroy() { /* cleanup */ }
}
const view = new EditorView(document.body, {
state: EditorState.create({ schema }),
nodeViews: {
paragraph: (node, view, getPos) => new FancyParagraph(node, view, getPos)
}
})
```
--------------------------------
### Serialize Slice for Clipboard
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use `serializeForClipboard` to get DOM and text representations of a slice, suitable for clipboard operations. Requires `EditorView`, `EditorState`, and `schema` imports.
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
import { TextSelection } from "prosemirror-state"
const view = new EditorView(document.body, {
state: EditorState.create({ schema })
})
// Get the slice for the current selection and put it on the clipboard
const slice = view.state.selection.content()
const { dom, text } = view.serializeForClipboard(slice)
navigator.clipboard.write([
new ClipboardItem({
"text/html": new Blob([dom.innerHTML], { type: "text/html" }),
"text/plain": new Blob([text], { type: "text/plain" })
})
])
```
--------------------------------
### Get Viewport Coordinates for Document Position
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use `coordsAtPos` to get the bounding box of a document position in viewport coordinates. This is useful for positioning UI elements relative to the cursor.
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema })
})
function showTooltipAtCursor(view: EditorView) {
const { head } = view.state.selection
const coords = view.coordsAtPos(head)
const tooltip = document.getElementById("tooltip")!
tooltip.style.left = coords.left + "px"
tooltip.style.top = coords.top + "px"
tooltip.hidden = false
}
// Call whenever selection changes
showTooltipAtCursor(view)
```
--------------------------------
### Get DOM Node for Document Position
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use `nodeDOM` to retrieve the outermost DOM node representing the document node immediately after a given position. Returns null if the position is not in front of a node or if the node uses a custom opaque view.
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema })
})
// Get the bounding rect of the first block node (at position 0)
const domNode = view.nodeDOM(0)
if (domNode instanceof HTMLElement) {
const rect = domNode.getBoundingClientRect()
console.log("First node rect:", rect.top, rect.left, rect.width, rect.height)
}
```
--------------------------------
### Create and Mount EditorView
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Instantiates an EditorView and mounts it into the DOM. The `place` argument can be a DOM node, a callback function, or an object with a `mount` property. The `dispatchTransaction` callback is essential for updating the editor state.
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
import { exampleSetup } from "prosemirror-example-setup"
const state = EditorState.create({
schema,
plugins: exampleSetup({ schema })
})
// Mount into a DOM node
const view = new EditorView(document.querySelector("#editor")!, {
state,
dispatchTransaction(tr) {
// This is where you integrate with external state management
const newState = view.state.apply(tr)
view.updateState(newState)
}
})
// Mount via a function
const view2 = new EditorView(
(editorDOM) => document.body.prepend(editorDOM),
{ state }
)
// Reuse an existing element
const mountEl = document.getElementById("existing-div") as HTMLElement
const view3 = new EditorView({ mount: mountEl }, { state })
```
--------------------------------
### Import ProseMirror CSS for Rendering
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Import the default prosemirror.css stylesheet to ensure correct rendering of the editor, including whitespace handling, selection display, and node selection outlines.
```typescript
// In a bundler (webpack, vite, etc.)
import "prosemirror-view/style/prosemirror.css"
// Or in HTML:
//
// The stylesheet defines:
// .ProseMirror — root editor element styles
// .ProseMirror-selectednode — 2px solid #8cf outline for node selections
// .ProseMirror-hideselection — hides native selection (used during drag)
// img.ProseMirror-separator — inline separator image reset
// You can extend/override without editing the file:
const style = document.createElement("style")
style.textContent = `
.ProseMirror { min-height: 200px; padding: 8px 12px; outline: none; }
.ProseMirror-selectednode { outline-color: #4a90d9; }
.search-match { background: rgba(255, 200, 0, 0.4); }
`
document.head.appendChild(style)
```
--------------------------------
### Manage decorations with DecorationSet
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
DecorationSet manages decorations efficiently. Use `create` to build a set, `find` to query it, and `map` to update it with document changes using a Mapping. The `onRemove` callback can be used to handle removed decorations.
```typescript
import { Decoration, DecorationSet } from "prosemirror-view"
import { EditorState, Plugin } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const commentPlugin = new Plugin({
state: {
init(_, state) {
return DecorationSet.create(state.doc, [
Decoration.inline(1, 4, { class: "comment" }, { id: "c1" }),
Decoration.inline(6, 9, { class: "comment" }, { id: "c2" })
])
},
apply(tr, set) {
// Keep decoration positions in sync as the document changes
set = set.map(tr.mapping, tr.doc, {
onRemove(spec) { console.log("Decoration removed:", spec.id) }
})
return set
}
},
props: {
decorations(state) { return commentPlugin.getState(state) }
}
})
// Query decorations in a range
const pluginState = commentPlugin.getState(
EditorState.create({ schema, plugins: [commentPlugin] })
)!
const inRange = pluginState.find(0, 10, spec => spec.id === "c1")
console.log("Found decorations:", inRange.length) // 1
```
--------------------------------
### EditorView Constructor
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Creates a new EditorView instance, which renders an EditorState into a DOM element and handles user interactions. The `place` argument can be a DOM node, a callback function, or an object with a `mount` property. The second argument is an object containing editor props, including the `state` and a `dispatchTransaction` callback.
```APIDOC
## EditorView Constructor
### Description
Creates the editor view and mounts it into the page. `place` may be a DOM node to append to, a callback `(editor) => void` that inserts the element, or an object `{ mount: HTMLElement }` to reuse an existing element. Pass `null` to keep the view detached.
### Parameters
#### `place`
- **Type**: DOM Node, `(editor: HTMLElement) => void`, or `{ mount: HTMLElement }`
- **Description**: The location or method to mount the editor view.
#### `props`
- **Type**: Object
- **Description**: Configuration object for the editor view.
- **`state`** (EditorState) - Required - The initial editor state.
- **`dispatchTransaction`** ((tr: Transaction) => void) - Optional - Callback to handle transaction dispatching.
### Request Example
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
import { exampleSetup } from "prosemirror-example-setup"
const state = EditorState.create({
schema,
plugins: exampleSetup({ schema })
})
// Mount into a DOM node
const view = new EditorView(document.querySelector("#editor")!, {
state,
dispatchTransaction(tr) {
// This is where you integrate with external state management
const newState = view.state.apply(tr)
view.updateState(newState)
}
})
// Mount via a function
const view2 = new EditorView(
(editorDOM) => document.body.prepend(editorDOM),
{ state }
)
// Reuse an existing element
const mountEl = document.getElementById("existing-div") as HTMLElement
const view3 = new EditorView({ mount: mountEl }, { state })
```
```
--------------------------------
### CSS — prosemirror.css
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
The package includes a `style/prosemirror.css` stylesheet that must be imported for correct rendering. It defines styles for the root editor element, selected nodes, hidden selections, and separator images.
```APIDOC
## CSS — prosemirror.css
The package ships `style/prosemirror.css` which must be imported alongside the JS to ensure correct rendering. It sets up `white-space`, selection hiding, the `.ProseMirror-selectednode` outline, and separator image rules.
```typescript
// In a bundler (webpack, vite, etc.)
import "prosemirror-view/style/prosemirror.css"
// Or in HTML:
//
// The stylesheet defines:
// .ProseMirror — root editor element styles
// .ProseMirror-selectednode — 2px solid #8cf outline for node selections
// .ProseMirror-hideselection — hides native selection (used during drag)
// img.ProseMirror-separator — inline separator image reset
// You can extend/override without editing the file:
const style = document.createElement("style")
style.textContent = `
.ProseMirror { min-height: 200px; padding: 8px 12px; outline: none; }
.ProseMirror-selectednode { outline-color: #4a90d9; }
.search-match { background: rgba(255, 200, 0, 0.4); }
`
document.head.appendChild(style)
```
```
--------------------------------
### Create Decoration Widget
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use `Decoration.widget` to insert DOM nodes at specific positions without altering the document model. Widgets are automatically repositioned. Requires `EditorView`, `Decoration`, `DecorationSet`, `EditorState`, and `Plugin` imports.
```typescript
import { EditorView, Decoration, DecorationSet } from "prosemirror-view"
import { EditorState, Plugin } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const cursorPlugin = new Plugin({
props: {
decorations(state) {
const { head } = state.selection
const widget = Decoration.widget(
head,
(view, getPos) => {
const span = document.createElement("span")
span.className = "cursor-label"
span.textContent = `¶${getPos() ?? "?"}`
return span
},
{
side: 1, // place after cursor
key: "cursor-label", // stable key avoids unnecessary redraws
destroy(node) { console.log("Widget removed", node) }
}
)
return DecorationSet.create(state.doc, [widget])
}
}
})
const view = new EditorView(document.body, {
state: EditorState.create({ schema, plugins: [cursorPlugin] })
})
```
--------------------------------
### Add and remove decorations using DecorationSet
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Create new DecorationSet instances by adding or removing decorations. The original set remains unchanged. Both `add` and `remove` methods require the current document to rebuild the internal tree structure.
```typescript
import { Decoration, DecorationSet } from "prosemirror-view"
import { EditorState, Plugin } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
let decoSet = DecorationSet.empty
const state = EditorState.create({ schema })
// Add two decorations
const d1 = Decoration.inline(1, 3, { class: "highlight" })
const d2 = Decoration.widget(5, document.createElement("span"))
decoSet = decoSet.add(state.doc, [d1, d2])
console.log(decoSet.find().length) // 2
// Remove one by identity
decoSet = decoSet.remove([d1])
console.log(decoSet.find().length) // 1
```
--------------------------------
### MarkView Interface
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Implement the MarkView interface to provide a custom DOM representation for mark types. Mark views offer `dom`, optional `contentDOM`, `ignoreMutation`, and `destroy`.
```APIDOC
## MarkView Interface
Implement `MarkView` to give a mark type a custom DOM representation. Unlike `NodeView`, mark views cannot intercept events; they provide only `dom`, optional `contentDOM`, `ignoreMutation`, and `destroy`.
```typescript
import { EditorView, MarkView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { Mark } from "prosemirror-model"
import { schema } from "prosemirror-schema-basic"
class LinkView implements MarkView {
dom: HTMLAnchorElement
contentDOM: HTMLAnchorElement // same element — mark content goes inside
constructor(mark: Mark, _view: EditorView, _inline: boolean) {
this.dom = document.createElement("a")
this.dom.href = mark.attrs.href
this.dom.title = mark.attrs.title || mark.attrs.href
this.dom.target = "_blank"
this.dom.rel = "noopener noreferrer"
this.contentDOM = this.dom
}
destroy() { /* any teardown */ }
}
const view = new EditorView(document.body, {
state: EditorState.create({ schema }),
markViews: {
link: (mark, view, inline) => new LinkView(mark, view, inline)
}
})
```
```
--------------------------------
### Decoration.widget
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Creates a widget decoration that inserts a DOM node at a specific position in the editor's document without altering the document model. These widgets are automatically repositioned as the document content changes.
```APIDOC
## Decoration.widget
Inserts an arbitrary DOM node into the rendered document at a given position without modifying the underlying document model. Widgets are repositioned automatically as the document changes.
### Method
`Decoration.widget(pos: number, toDOM: (view: EditorView, getPos: () => number | undefined) => HTMLElement, spec?: { side?: number, key?: string, destroy?: (node: HTMLElement) => void }): Decoration`
### Parameters
- **pos** (number) - The document position where the widget should be placed.
- **toDOM** (function) - A function that returns the DOM element for the widget. It receives the `EditorView` and a `getPos` function.
- **spec** (object, optional) - Additional specifications for the widget.
- **side** (number, optional) - Determines placement relative to the cursor (e.g., 1 for after, -1 for before).
- **key** (string, optional) - A stable key to prevent unnecessary redraws.
- **destroy** (function, optional) - A callback function executed when the widget is removed.
### Response
- **Decoration** - A widget decoration object.
### Request Example
```typescript
import { EditorView, Decoration, DecorationSet } from "prosemirror-view"
import { EditorState, Plugin } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const cursorPlugin = new Plugin({
props: {
decorations(state) {
const { head } = state.selection
const widget = Decoration.widget(
head,
(view, getPos) => {
const span = document.createElement("span")
span.className = "cursor-label"
span.textContent = `¶${getPos() ?? "?"}`
return span
},
{
side: 1,
key: "cursor-label",
destroy(node) { console.log("Widget removed", node) }
}
)
return DecorationSet.create(state.doc, [widget])
}
}
})
const view = new EditorView(document.body, {
state: EditorState.create({ schema, plugins: [cursorPlugin] })
})
```
```
--------------------------------
### NodeView Interface
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Implement the NodeView interface to provide a custom DOM representation, event handling, and nested contentDOM for specific node types in ProseMirror.
```APIDOC
## NodeView Interface
Implement `NodeView` to give a specific node type a fully custom DOM representation, event handling, and optional nested `contentDOM` for ProseMirror-managed child rendering.
```typescript
import { EditorView, NodeView, Decoration, DecorationSource } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { Node } from "prosemirror-model"
import { schema } from "prosemirror-schema-basic"
class FancyParagraph implements NodeView {
dom: HTMLElement
contentDOM: HTMLElement
constructor(
private node: Node,
private view: EditorView,
private getPos: () => number | undefined
) {
this.dom = document.createElement("div")
this.dom.className = "fancy-para"
const inner = document.createElement("p")
this.dom.appendChild(inner)
this.contentDOM = inner // ProseMirror renders children here
}
update(node: Node, _decos: readonly Decoration[], _inner: DecorationSource) {
if (node.type !== this.node.type) return false
this.node = node
this.dom.classList.toggle("has-content", node.content.size > 0)
return true
}
selectNode() { this.dom.classList.add("selected") }
deselectNode() { this.dom.classList.remove("selected") }
stopEvent(e: Event) { return e.type === "mousedown" } // absorb mousedowns
destroy() { /* cleanup */ }
}
const view = new EditorView(document.body, {
state: EditorState.create({ schema }),
nodeViews: {
paragraph: (node, view, getPos) => new FancyParagraph(node, view, getPos)
}
})
```
```
--------------------------------
### EditorView.domAtPos / EditorView.posAtDOM
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Provides bidirectional mapping between document positions and the real DOM. `domAtPos` maps a document position to a DOM node and offset, while `posAtDOM` performs the reverse conversion.
```APIDOC
## EditorView.domAtPos / EditorView.posAtDOM
### Description
`domAtPos` maps a document position to `{ node, offset }` in the real DOM. `posAtDOM` does the reverse. Both are useful when bridging ProseMirror and raw DOM APIs.
### Methods
- `domAtPos(pos: number, bias?: 1 | -1): { node: Node, offset: number }`
- `posAtDOM(node: Node, offset: number): number`
### Parameters
#### `domAtPos` Parameters
- **pos** (number) - The document position to map.
- **bias** (number, optional) - Determines whether to prefer the start (-1) or end (1) of a node if the position falls within it. Defaults to 1.
#### `posAtDOM` Parameters
- **node** (Node) - The DOM node.
- **offset** (number) - The offset within the DOM node.
### Request Example
```typescript
// Find the DOM node at position 3
const { node, offset } = view.domAtPos(3, 1)
// Translate a DOM position back
const pos = view.posAtDOM(node, offset)
```
### Response
#### `domAtPos` Success Response
- **node** (Node) - The DOM node corresponding to the position.
- **offset** (number) - The offset within the DOM node.
#### `posAtDOM` Success Response
- (number) - The document position.
#### Error Handling
`posAtDOM` may throw an error if the DOM position is outside the editor.
```
--------------------------------
### Apply Visual Decorations with the decorations Prop
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
The decorations prop accepts a function that returns a DecorationSource to visually annotate the document based on the current state. This function is invoked on every state update.
```typescript
import { EditorView, DecorationSet, Decoration } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema }),
decorations(state) {
const decos: Decoration[] = []
// Add a gutter widget at the start of each block node
state.doc.forEach((node, offset) => {
const gutter = document.createElement("span")
gutter.className = "line-number"
gutter.textContent = "¶"
decos.push(Decoration.widget(offset + 1, gutter, { side: -1 }))
})
// Highlight the entire selection range
const { from, to } = state.selection
if (from !== to) {
decos.push(Decoration.inline(from, to, { class: "selection-highlight" }))
}
return DecorationSet.create(state.doc, decos)
}
})
```
--------------------------------
### Query Editor Properties with someProp
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use `someProp` to query a property value across direct props, direct plugins, and state plugins, returning the first truthy result. Useful for custom plugin logic. Requires `Plugin`, `EditorState`, `EditorView`, and `schema` imports.
```typescript
import { Plugin, EditorState } from "prosemirror-state"
import { EditorView } from "prosemirror-view"
import { schema } from "prosemirror-schema-basic"
const analyticsPlugin = new Plugin({
props: {
handleClick(_view, pos) {
console.log("Click at position", pos)
return false
}
}
})
const view = new EditorView(document.body, {
state: EditorState.create({ schema, plugins: [analyticsPlugin] }),
// Check if ANY prop declares a custom editable guard
editable: (state) => true
})
// Query a prop value across all sources
const isEditable = view.someProp("editable", fn => fn(view.state))
console.log("Editor is editable:", isEditable !== false)
```
--------------------------------
### Map Between DOM and Document Positions
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use `domAtPos` to find the DOM node and offset for a document position, and `posAtDOM` to do the reverse. These are essential for integrating with raw DOM APIs.
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema })
})
// Find the DOM node at position 3 (prefer content after the position)
const { node, offset } = view.domAtPos(3, 1)
console.log("DOM node:", node.nodeName, "offset:", offset)
// Translate a DOM position back (e.g. from a custom event handler)
try {
const pos = view.posAtDOM(node, offset)
console.log("Document position:", pos)
} catch (e) {
console.warn("DOM position is outside the editor")
}
```
--------------------------------
### EditorView.someProp
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Queries a specific property across all plugin resolvers and direct props of the editor view. It returns the first truthy value found by applying a given function to each non-undefined property value.
```APIDOC
## EditorView.someProp
Iterates prop resolvers (direct props → direct plugins → state plugins) and returns the first truthy result of calling `f` on each non-undefined value. Used internally and useful in plugins.
### Method
`someProp(propName: string, f: (value: any) => any): any`
### Parameters
- **propName** (string) - The name of the property to query.
- **f** (function) - A function to apply to each property value. It should return a truthy value to stop iteration and return the result, or a falsy value to continue.
### Response
- **any** - The first truthy result returned by the function `f`, or `undefined` if no truthy result is found.
### Request Example
```typescript
import { Plugin, EditorState } from "prosemirror-state"
import { EditorView } from "prosemirror-view"
import { schema } from "prosemirror-schema-basic"
const analyticsPlugin = new Plugin({
props: {
handleClick(_view, pos) {
console.log("Click at position", pos)
return false
}
}
})
const view = new EditorView(document.body, {
state: EditorState.create({ schema, plugins: [analyticsPlugin] }),
editable: (state) => true
})
const isEditable = view.someProp("editable", fn => fn(view.state))
console.log("Editor is editable:", isEditable !== false)
```
```
--------------------------------
### EditorProps - Event Handlers
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Handle various editor events such as keydown, click, paste, and drop by returning `true` to prevent further processing, or `false`/`undefined` to allow default behavior.
```APIDOC
## EditorProps — event handler props
All event-handler props (`handleKeyDown`, `handleClick`, `handlePaste`, `handleDrop`, etc.) follow the same pattern: return `true` to mark the event as handled (preventing further processing), or `false`/`undefined` to pass through.
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema }),
handleKeyDown(view, event) {
if (event.key === "Tab") {
event.preventDefault()
view.dispatch(view.state.tr.insertText(" "))
return true
}
return false
},
handleClick(view, pos, event) {
if (event.ctrlKey) {
console.log("Ctrl-click at position", pos)
return true
}
return false
},
handlePaste(view, event, slice) {
console.log("Pasting", slice.content.childCount, "nodes")
return false // allow default paste
},
handleDrop(view, event, slice, moved) {
console.log(`${moved ? "Moved" : "Copied"} content:`, slice)
return false
},
handleDOMEvents: {
focus(view) {
view.dom.classList.add("is-focused")
return false
},
blur(view) {
view.dom.classList.remove("is-focused")
return false
}
}
})
```
```
--------------------------------
### Programmatically Trigger Paste Operations
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use `pasteHTML` and `pasteText` to simulate pasting content into the editor. These methods respect configured paste transformation and handling hooks.
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema }),
handlePaste(view, _event, slice) {
console.log("Pasted slice has", slice.content.childCount, "top-level nodes")
return false // let default handling proceed
}
})
// Simulate an HTML paste
view.pasteHTML("
Bold text pasted programmatically
")
// Simulate a plain-text paste
view.pasteText("Plain text\nWith two lines")
```
--------------------------------
### EditorView.serializeForClipboard
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Serializes a Slice of content from the editor's current selection into a format suitable for clipboard operations. It returns an object containing DOM nodes, plain text, and the slice itself.
```APIDOC
## EditorView.serializeForClipboard
Serializes a `Slice` the same way the editor would for a clipboard copy operation, returning `{ dom, text, slice }`. The `dom` element can be inspected or used with the Clipboard API.
### Method
`serializeForClipboard(slice: Slice): { dom: HTMLElement, text: string, slice: Slice }`
### Parameters
- **slice** (Slice) - The slice of content to serialize.
### Response
- **dom** (HTMLElement) - A DOM element representing the serialized content (e.g., for HTML).
- **text** (string) - The plain text representation of the serialized content.
- **slice** (Slice) - The original slice object.
### Request Example
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema })
})
const slice = view.state.selection.content()
const { dom, text } = view.serializeForClipboard(slice)
navigator.clipboard.write([
new ClipboardItem({
"text/html": new Blob([dom.innerHTML], { type: "text/html" }),
"text/plain": new Blob([text], { type: "text/plain" })
})
])
```
```
--------------------------------
### EditorProps — decorations prop
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Provides a function that returns a `DecorationSource` to visually decorate the document based on the current state. This function is invoked on every state update.
```APIDOC
## EditorProps — decorations prop
Provide a function returning a `DecorationSource` to decorate the document in response to the current state. Called on every state update.
```typescript
import { EditorView, DecorationSet, Decoration } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema }),
decorations(state) {
const decos: Decoration[] = []
// Add a gutter widget at the start of each block node
state.doc.forEach((node, offset) => {
const gutter = document.createElement("span")
gutter.className = "line-number"
gutter.textContent = "¶"
decos.push(Decoration.widget(offset + 1, gutter, { side: -1 }))
})
// Highlight the entire selection range
const { from, to } = state.selection
if (from !== to) {
decos.push(Decoration.inline(from, to, { class: "selection-highlight" }))
}
return DecorationSet.create(state.doc, decos)
}
})
```
```
--------------------------------
### EditorView.setProps / EditorView.update
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Updates the properties of the editor view. `setProps` merges new properties with existing ones, while `update` replaces all properties with a new set. Both methods trigger an immediate DOM update.
```APIDOC
## EditorView.setProps / EditorView.update
### Description
`update` replaces **all** props at once; `setProps` merges a partial object into the existing props. Both trigger an immediate DOM update.
### Parameters
#### `props` (for `setProps`)
- **Type**: Object
- **Description**: An object containing properties to merge into the existing props.
#### `props` (for `update`)
- **Type**: Object
- **Description**: An object containing all properties to set for the editor view.
### Request Example
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
import { DecorationSet, Decoration } from "prosemirror-view"
const view = new EditorView(document.body, {
state: EditorState.create({ schema })
})
// Add a decorations prop without rebuilding everything else
view.setProps({
decorations(state) {
// Highlight positions 1-5 in yellow
return DecorationSet.create(state.doc, [
Decoration.inline(1, 5, { style: "background: yellow" })
])
}
})
// Make the editor read-only
view.setProps({ editable: () => false })
// Full replacement: provide all required fields
view.update({
state: view.state,
editable: () => true,
attributes: { class: "my-editor", "aria-label": "Rich text editor" }
})
```
```
--------------------------------
### Convert Coordinates to Document Position
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use `posAtCoords` to find the document position corresponding to viewport coordinates. It returns the document position and the position of the surrounding node.
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema }),
handleClick(view, _pos, event) {
const result = view.posAtCoords({ left: event.clientX, top: event.clientY })
if (result) {
console.log("Clicked at doc position:", result.pos)
console.log("Inside node at:", result.inside) // -1 means top-level
}
return false
}
})
```
--------------------------------
### Apply DOM attributes to inline nodes with Decoration.inline
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use Decoration.inline to apply DOM attributes to all inline nodes within a document range. This is useful for highlights, search matches, or annotations. Ensure necessary imports from 'prosemirror-view' and 'prosemirror-state'.
```typescript
import { EditorView, Decoration, DecorationSet } from "prosemirror-view"
import { EditorState, Plugin } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
// Highlight all occurrences of a search term
function buildSearchDecorations(state: EditorState, term: string) {
const decos: Decoration[] = []
const regex = new RegExp(term, "gi")
state.doc.descendants((node, pos) => {
if (!node.isText) return
let match
while ((match = regex.exec(node.text!)) !== null) {
decos.push(
Decoration.inline(pos + match.index, pos + match.index + match[0].length, {
class: "search-match",
style: "background: #ff06"
})
)
}
})
return DecorationSet.create(state.doc, decos)
}
const searchPlugin = new Plugin({
props: {
decorations(state) {
return buildSearchDecorations(state, "prosemirror")
}
}
})
const view = new EditorView(document.body, {
state: EditorState.create({ schema, plugins: [searchPlugin] })
})
```
--------------------------------
### EditorView.posAtCoords
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Converts viewport coordinates (left, top) into a document position. It returns an object containing the document position (`pos`) and the position of the surrounding node (`inside`). Returns `null` if the coordinates are outside the editor.
```APIDOC
## EditorView.posAtCoords
### Description
Converts viewport `(left, top)` coordinates into a document position. Returns `{ pos, inside }` where `inside` is the position of the surrounding node, or `null` if the coordinates are outside the editor.
### Method
`posAtCoords(coords: { left: number, top: number }): { pos: number, inside: number } | null`
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Request Example
```typescript
const result = view.posAtCoords({ left: event.clientX, top: event.clientY })
if (result) {
console.log("Clicked at doc position:", result.pos)
console.log("Inside node at:", result.inside)
}
```
### Response
#### Success Response
- **pos** (number) - The document position.
- **inside** (number) - The position of the surrounding node, or -1 if at the top level.
#### Response Example
```json
{
"pos": 10,
"inside": 5
}
```
```
--------------------------------
### Dispatch Transaction with EditorView
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Dispatches a transaction to the editor. If a `dispatchTransaction` prop is set, it will be called; otherwise, the transaction is applied automatically. This method is pre-bound to the view instance.
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema })
})
// Insert text at the current selection head
const { tr } = view.state
tr.insertText("Hello, ProseMirror!")
view.dispatch(tr)
// Bold the entire first paragraph (positions 1 to 4 in a trivial doc)
const boldMark = schema.marks.strong.create()
const tr2 = view.state.tr.addMark(1, 4, boldMark)
view.dispatch(tr2)
```
--------------------------------
### Manage Editor Focus
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Check if the editor has focus using `hasFocus` and programmatically focus it with `focus`. Useful for UI feedback and ensuring editor interactivity. Requires `EditorView`, `EditorState`, and `schema` imports.
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema })
})
document.getElementById("focus-btn")!.addEventListener("click", () => {
if (!view.hasFocus()) {
view.focus()
console.log("Editor focused")
}
})
```
--------------------------------
### EditorView.coordsAtPos
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Returns a viewport rectangle (`{ left, right, top, bottom }`) for a given document position. This is useful for positioning UI elements like tooltips or menus relative to the cursor.
```APIDOC
## EditorView.coordsAtPos
### Description
Returns a `{ left, right, top, bottom }` viewport rectangle for a given document position. Useful for positioning tooltips, menus, or inline widgets relative to the cursor.
### Method
`coordsAtPos(pos: number): { left: number, right: number, top: number, bottom: number }`
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Request Example
```typescript
const coords = view.coordsAtPos(head)
```
### Response
#### Success Response
- **left** (number) - The left coordinate of the rectangle.
- **right** (number) - The right coordinate of the rectangle.
- **top** (number) - The top coordinate of the rectangle.
- **bottom** (number) - The bottom coordinate of the rectangle.
#### Response Example
```json
{
"left": 100,
"right": 150,
"top": 50,
"bottom": 65
}
```
```
--------------------------------
### Apply DOM attributes to a specific block node with Decoration.node
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Use Decoration.node to apply DOM attributes to a single block or inline-block node. The decoration's boundaries must precisely align with the node's. The `spec` object can store arbitrary metadata.
```typescript
import { EditorView, Decoration, DecorationSet } from "prosemirror-view"
import { EditorState, Plugin, NodeSelection } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
// Highlight the currently selected node
const selectedNodePlugin = new Plugin({
props: {
decorations(state) {
const { selection } = state
if (!(selection instanceof NodeSelection)) return null
return DecorationSet.create(state.doc, [
Decoration.node(selection.from, selection.to, {
class: "node-selected",
style: "outline: 2px solid royalblue"
}, { type: "node-highlight" })
])
}
}
})
const view = new EditorView(document.body, {
state: EditorState.create({ schema, plugins: [selectedNodePlugin] })
})
```
--------------------------------
### EditorView.hasFocus / EditorView.focus
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Manages the focus state of the editor. `hasFocus` checks if the editor element currently has focus, while `focus` programmatically sets the focus to the editor without causing the page to scroll.
```APIDOC
## EditorView.hasFocus / EditorView.focus
`hasFocus` returns whether the editor element is the active focused element. `focus` programmatically focuses the editor without scrolling the page.
### Methods
- **hasFocus(): boolean** - Returns `true` if the editor has focus, `false` otherwise.
- **focus(): void** - Programmatically sets focus to the editor.
### Request Example
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema })
})
document.getElementById("focus-btn")!.addEventListener("click", () => {
if (!view.hasFocus()) {
view.focus()
console.log("Editor focused")
}
})
```
```
--------------------------------
### EditorView.dispatch
Source: https://context7.com/prosemirror/prosemirror-view/llms.txt
Dispatches a ProseMirror transaction. If a `dispatchTransaction` callback is provided in the editor's props, it will be called with the transaction. Otherwise, the transaction is applied to the current state automatically. This method is pre-bound to the view instance.
```APIDOC
## EditorView.dispatch
### Description
Dispatches a transaction. If `dispatchTransaction` is provided in props it is called; otherwise the transaction is applied to the current state automatically. The method is pre-bound to the view instance.
### Parameters
#### `tr`
- **Type**: Transaction
- **Description**: The transaction to dispatch.
### Request Example
```typescript
import { EditorView } from "prosemirror-view"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
const view = new EditorView(document.body, {
state: EditorState.create({ schema })
})
// Insert text at the current selection head
const { tr } = view.state
tr.insertText("Hello, ProseMirror!")
view.dispatch(tr)
// Bold the entire first paragraph (positions 1 to 4 in a trivial doc)
const boldMark = schema.marks.strong.create()
const tr2 = view.state.tr.addMark(1, 4, boldMark)
view.dispatch(tr2)
```
```