Paste rules allow you to modify content when it’s pasted or dragged into the editor. They’re perfect for auto-linking URLs, converting markdown to rich text, or cleaning up pasted content.
Overview
ProseKit provides two types of paste rules:
Custom Paste Rules : Transform the entire pasted slice
Mark Paste Rules : Apply marks based on regex patterns
Paste rules run before the content is inserted into the document, giving you full control over the transformation.
Custom Paste Rules
Define custom logic to transform pasted content.
import { definePasteRule } from '@prosekit/extensions/paste-rule'
const extension = definePasteRule ({
handler : ({ slice , view , plain }) => {
if ( plain ) {
// Skip transformation for plain text paste (Shift+Paste)
return slice
}
// Transform the slice
// ...
return transformedSlice
},
})
Handler Options
The content being pasted as a ProseMirror Slice.
Whether the content is being pasted as plain text (true when Shift key is held).
Mark Paste Rules
Automatically apply marks to pasted text that matches a regex pattern.
Basic Usage
import { defineMarkPasteRule } from '@prosekit/extensions/paste-rule'
const autoLinkExtension = defineMarkPasteRule ({
regex: / ( https ? : \/\/ [ ^ \s ] + ) / g ,
type: 'link' ,
getAttrs : ( match ) => ({
href: match [ 1 ],
}),
})
The regex pattern must have the g flag to match all instances in the pasted content.
With Conditional Attributes
import { defineMarkPasteRule } from '@prosekit/extensions/paste-rule'
const smartLinkExtension = defineMarkPasteRule ({
regex: / ( https ? : \/\/ [ ^ \s ] + ) / g ,
type: 'link' ,
getAttrs : ( match ) => {
const url = match [ 1 ]
// Only link if it's a valid URL
try {
new URL ( url )
return { href: url }
} catch {
return false // Don't apply the mark
}
},
})
Custom Skip Logic
import { defineMarkPasteRule } from '@prosekit/extensions/paste-rule'
const highlightExtension = defineMarkPasteRule ({
regex: /== ( . *? ) ==/ g ,
type: 'highlight' ,
shouldSkip : ( node ) => {
// Don't apply in code blocks or if already highlighted
return (
node . type . spec . code ||
node . marks . some (( mark ) => mark . type . name === 'highlight' )
)
},
})
API Reference
defineMarkPasteRule
The regular expression to match against. Must have the g flag to match all instances.
type
string | MarkType
required
The mark type to apply to matched text.
getAttrs
(match: RegExpExecArray) => Attrs | null | undefined | false
Function to compute attributes for the mark. Return false to skip applying the mark for this match. Default: null (empty attributes)
shouldSkip
(node: ProseMirrorNode) => boolean
Function to determine if a text node should be skipped. Default: Skip code nodes and nodes that already have the target mark.
Real-World Examples
Auto-Link URLs
import { defineMarkPasteRule } from '@prosekit/extensions/paste-rule'
const autoLinkExtension = defineMarkPasteRule ({
regex: / ( https ? : \/\/ (?: www \. ) ? [ -a-zA-Z0-9@:%._ \+ ~#= ] {1,256} \. [ a-zA-Z0-9() ] {1,6} \b (?: [ -a-zA-Z0-9()@:%_ \+ .~#?& \/ = ] * )) / g ,
type: 'link' ,
getAttrs : ( match ) => ({
href: match [ 1 ],
}),
})
Convert Markdown Links
import { definePasteRule } from '@prosekit/extensions/paste-rule'
import { Fragment , Slice } from '@prosekit/pm/model'
const markdownLinkExtension = definePasteRule ({
handler : ({ slice , view , plain }) => {
if ( plain ) return slice
// Transform [text](url) to link marks
const markdownLinkRegex = / \[ ( [ ^ \] ] + ) \]\( ( [ ^ ) ] + ) \) / g
// Process slice content...
// This is a simplified example
return transformedSlice
},
})
Clean HTML on Paste
import { definePasteRule } from '@prosekit/extensions/paste-rule'
const cleanHtmlExtension = definePasteRule ({
handler : ({ slice , view , plain }) => {
if ( plain ) return slice
// Remove unwanted attributes or nodes
// For example, strip inline styles
const cleanedSlice = removeInlineStyles ( slice )
return cleanedSlice
},
})
function removeInlineStyles ( slice : Slice ) : Slice {
// Implementation to clean the slice
// ...
return slice
}
Email Address Detection
import { defineMarkPasteRule } from '@prosekit/extensions/paste-rule'
const emailLinkExtension = defineMarkPasteRule ({
regex: / ( [ a-zA-Z0-9._%+- ] + @ [ a-zA-Z0-9.- ] + \. [ a-zA-Z ] {2,} ) / g ,
type: 'link' ,
getAttrs : ( match ) => ({
href: `mailto: ${ match [ 1 ] } ` ,
}),
})
Markdown Bold to Rich Text
import { defineMarkPasteRule } from '@prosekit/extensions/paste-rule'
const markdownBoldExtension = defineMarkPasteRule ({
regex: / \*\* ( [ ^ * ] + ) \*\* / g ,
type: 'bold' ,
getAttrs : ( match ) => {
// Return null to use default attributes
return null
},
})
Combining Rules
import { union } from '@prosekit/core'
import { defineMarkPasteRule } from '@prosekit/extensions/paste-rule'
const pasteExtensions = union ([
// Auto-link URLs
defineMarkPasteRule ({
regex: / ( https ? : \/\/ [ ^ \s ] + ) / g ,
type: 'link' ,
getAttrs : ( match ) => ({ href: match [ 1 ] }),
}),
// Auto-link emails
defineMarkPasteRule ({
regex: / ( [ a-zA-Z0-9._%+- ] + @ [ a-zA-Z0-9.- ] + \. [ a-zA-Z ] {2,} ) / g ,
type: 'link' ,
getAttrs : ( match ) => ({ href: `mailto: ${ match [ 1 ] } ` }),
}),
// Convert markdown bold
defineMarkPasteRule ({
regex: / \*\* ( [ ^ * ] + ) \*\* / g ,
type: 'bold' ,
}),
// Convert markdown italic
defineMarkPasteRule ({
regex: / \* ( [ ^ * ] + ) \* / g ,
type: 'italic' ,
}),
])
Use Cases
Auto-Linking Automatically convert URLs and email addresses to clickable links when pasted.
Markdown Conversion Convert markdown syntax to rich text formatting on paste.
Content Cleaning Strip unwanted formatting, styles, or attributes from pasted content.
Smart Formatting Apply intelligent formatting based on the pasted content’s patterns.
Tips
Check the plain parameter to skip transformations when users paste with Shift (paste as plain text).
Mark paste rules are more efficient than custom paste rules when you only need to apply marks based on patterns.
Be careful with aggressive paste rules that might remove content users want to keep. Consider providing a way to undo paste transformations.